From f4da2d56b7785569e1b88625bb766675b20438cc Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 3 Mar 2026 08:38:42 +0000 Subject: [PATCH 001/655] 8378684: Fix -Wdeprecated-declarations warnings from gtest by clang23 Reviewed-by: erikj, kbarrett --- make/hotspot/lib/CompileGtest.gmk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 327014b1e9d..4b21d481049 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -63,6 +63,10 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ unused-result zero-as-null-pointer-constant, \ DISABLED_WARNINGS_clang := format-nonliteral undef unused-result \ zero-as-null-pointer-constant, \ + $(comment Disable deprecated-declarations warnings to workaround) \ + $(comment clang18+glibc12 bug https://github.com/llvm/llvm-project/issues/76515) \ + $(comment until the clang bug has been fixed) \ + DISABLED_WARNINGS_clang_gtest-all.cc := deprecated-declarations, \ DISABLED_WARNINGS_microsoft := 4530, \ DEFAULT_CFLAGS := false, \ CFLAGS := $(JVM_CFLAGS) \ From 7e9e64966b47c788c91f934b5fca5cd31ad465b3 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 3 Mar 2026 08:39:04 +0000 Subject: [PATCH 002/655] 8378083: Mark shenandoah/generational/TestOldGrowthTriggers.java as flagless Reviewed-by: wkemper --- .../gc/shenandoah/generational/TestOldGrowthTriggers.java | 2 +- test/lib/jdk/test/lib/process/ProcessTools.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java index a66b9161c7e..7af81fabe13 100644 --- a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java +++ b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java @@ -27,6 +27,7 @@ * @summary Test that growth of old-gen triggers old-gen marking * @key intermittent * @requires vm.gc.Shenandoah + * @requires vm.flagless * @library /test/lib * @run driver TestOldGrowthTriggers */ @@ -34,7 +35,6 @@ import java.util.*; import java.math.BigInteger; -import jdk.test.lib.Asserts; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; diff --git a/test/lib/jdk/test/lib/process/ProcessTools.java b/test/lib/jdk/test/lib/process/ProcessTools.java index fe9c1de9f30..e7dd20c6286 100644 --- a/test/lib/jdk/test/lib/process/ProcessTools.java +++ b/test/lib/jdk/test/lib/process/ProcessTools.java @@ -575,7 +575,7 @@ public final class ProcessTools { * "test.vm.opts" and "test.java.opts" and this method will * not do that. * - *

If you still chose to use + *

If you still choose to use * createLimitedTestJavaProcessBuilder() you should probably use * it in combination with @requires vm.flagless JTREG * anotation as to not waste energy and test resources. @@ -609,7 +609,7 @@ public final class ProcessTools { * "test.vm.opts" and "test.java.opts" and this method will * not do that. * - *

If you still chose to use + *

If you still choose to use * createLimitedTestJavaProcessBuilder() you should probably use * it in combination with @requires vm.flagless JTREG * anotation as to not waste energy and test resources. From c0c8bdd294c5ca56307123c7f10ec10ba33c4bca Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 3 Mar 2026 09:23:22 +0000 Subject: [PATCH 003/655] 8378948: Remove unused local variable in RunnerGSInserterThread Reviewed-by: syan, jiefu --- test/hotspot/gtest/utilities/test_concurrentHashtable.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp index 77055e92256..8094e93b944 100644 --- a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp +++ b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp @@ -888,7 +888,6 @@ public: virtual ~RunnerGSInserterThread(){} void premain() { - volatile bool timeout = false; _start = START; _range = RANGE; CHTTestThread* tt[GSTEST_THREAD_COUNT]; From 0b183bf2d608bedf118607b1471fbf1e68813a08 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Tue, 3 Mar 2026 09:39:06 +0000 Subject: [PATCH 004/655] 8312116: GenShen: make instantaneous allocation rate triggers more timely Reviewed-by: wkemper --- .../shenandoahAdaptiveHeuristics.cpp | 559 ++++++++++++++++-- .../shenandoahAdaptiveHeuristics.hpp | 76 +++ .../shenandoahGenerationalHeuristics.cpp | 6 + .../shenandoahGenerationalHeuristics.hpp | 2 + .../heuristics/shenandoahHeuristics.cpp | 30 +- .../heuristics/shenandoahHeuristics.hpp | 33 +- .../heuristics/shenandoahYoungHeuristics.cpp | 3 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 1 + .../gc/shenandoah/shenandoahControlThread.cpp | 19 +- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 1 + .../share/gc/shenandoah/shenandoahFreeSet.cpp | 62 +- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 70 ++- .../share/gc/shenandoah/shenandoahFullGC.cpp | 4 +- .../gc/shenandoah/shenandoahGeneration.cpp | 7 +- .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../shenandoahGenerationalControlThread.cpp | 3 +- .../shenandoah/shenandoahGenerationalHeap.cpp | 22 +- .../shenandoah/shenandoahGenerationalHeap.hpp | 3 + .../share/gc/shenandoah/shenandoahHeap.cpp | 27 +- .../share/gc/shenandoah/shenandoahHeap.hpp | 3 + .../gc/shenandoah/shenandoahOldGeneration.cpp | 2 + .../shenandoah/shenandoahRegulatorThread.cpp | 16 +- .../shenandoah/shenandoahRegulatorThread.hpp | 3 + .../gc/shenandoah/shenandoah_globals.hpp | 53 ++ 24 files changed, 899 insertions(+), 108 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index 7a8bd55c795..ac8b3ebdf37 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -33,6 +33,7 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" +#include "gc/shenandoah/shenandoahYoungGeneration.hpp" #include "logging/log.hpp" #include "logging/logTag.hpp" #include "runtime/globals.hpp" @@ -59,14 +60,95 @@ const double ShenandoahAdaptiveHeuristics::HIGHEST_EXPECTED_AVAILABLE_AT_END = 0 const double ShenandoahAdaptiveHeuristics::MINIMUM_CONFIDENCE = 0.319; // 25% const double ShenandoahAdaptiveHeuristics::MAXIMUM_CONFIDENCE = 3.291; // 99.9% + +// To enable detection of GC time trends, we keep separate track of the recent history of gc time. During initialization, +// for example, the amount of live memory may be increasing, which is likely to cause the GC times to increase. This history +// allows us to predict increasing GC times rather than always assuming average recent GC time is the best predictor. +const size_t ShenandoahAdaptiveHeuristics::GC_TIME_SAMPLE_SIZE = 3; + +// We also keep separate track of recently sampled allocation rates for two purposes: +// 1. The number of samples examined to determine acceleration of allocation is represented by +// ShenandoahRateAccelerationSampleSize +// 2. The number of most recent samples averaged to determine a momentary allocation spike is represented by +// ShenandoahMomentaryAllocationRateSpikeSampleSize + +// Allocation rates are sampled by the regulator thread, which typically runs every ms. There may be jitter in the scheduling +// of the regulator thread. To reduce signal noise and synchronization overhead, we do not sample allocation rate with every +// iteration of the regulator. We prefer sample time longer than 1 ms so that there can be a statistically significant number +// of allocations occuring within each sample period. The regulator thread samples allocation rate only if at least +// ShenandoahAccelerationSamplePeriod ms have passed since it previously sampled the allocation rate. +// +// This trigger responds much more quickly than the traditional trigger, which monitors 100 ms spans. When acceleration is +// detected, the impact of acceleration on anticipated consumption of available memory is also much more impactful +// than the assumed constant allocation rate consumption of available memory. + ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics(ShenandoahSpaceInfo* space_info) : ShenandoahHeuristics(space_info), _margin_of_error_sd(ShenandoahAdaptiveInitialConfidence), _spike_threshold_sd(ShenandoahAdaptiveInitialSpikeThreshold), _last_trigger(OTHER), - _available(Moving_Average_Samples, ShenandoahAdaptiveDecayFactor) { } + _available(Moving_Average_Samples, ShenandoahAdaptiveDecayFactor), + _free_set(nullptr), + _previous_acceleration_sample_timestamp(0.0), + _gc_time_first_sample_index(0), + _gc_time_num_samples(0), + _gc_time_timestamps(NEW_C_HEAP_ARRAY(double, GC_TIME_SAMPLE_SIZE, mtGC)), + _gc_time_samples(NEW_C_HEAP_ARRAY(double, GC_TIME_SAMPLE_SIZE, mtGC)), + _gc_time_xy(NEW_C_HEAP_ARRAY(double, GC_TIME_SAMPLE_SIZE, mtGC)), + _gc_time_xx(NEW_C_HEAP_ARRAY(double, GC_TIME_SAMPLE_SIZE, mtGC)), + _gc_time_sum_of_timestamps(0), + _gc_time_sum_of_samples(0), + _gc_time_sum_of_xy(0), + _gc_time_sum_of_xx(0), + _gc_time_m(0.0), + _gc_time_b(0.0), + _gc_time_sd(0.0), + _spike_acceleration_buffer_size(MAX2(ShenandoahRateAccelerationSampleSize, 1+ShenandoahMomentaryAllocationRateSpikeSampleSize)), + _spike_acceleration_first_sample_index(0), + _spike_acceleration_num_samples(0), + _spike_acceleration_rate_samples(NEW_C_HEAP_ARRAY(double, _spike_acceleration_buffer_size, mtGC)), + _spike_acceleration_rate_timestamps(NEW_C_HEAP_ARRAY(double, _spike_acceleration_buffer_size, mtGC)) { + } -ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() {} +ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() { + FREE_C_HEAP_ARRAY(double, _spike_acceleration_rate_samples); + FREE_C_HEAP_ARRAY(double, _spike_acceleration_rate_timestamps); + FREE_C_HEAP_ARRAY(double, _gc_time_timestamps); + FREE_C_HEAP_ARRAY(double, _gc_time_samples); + FREE_C_HEAP_ARRAY(double, _gc_time_xy); + FREE_C_HEAP_ARRAY(double, _gc_time_xx); +} + +void ShenandoahAdaptiveHeuristics::initialize() { + ShenandoahHeuristics::initialize(); +} + +void ShenandoahAdaptiveHeuristics::post_initialize() { + ShenandoahHeuristics::post_initialize(); + _free_set = ShenandoahHeap::heap()->free_set(); + assert(!ShenandoahHeap::heap()->mode()->is_generational(), "ShenandoahGenerationalHeuristics overrides this method"); + compute_headroom_adjustment(); +} + +void ShenandoahAdaptiveHeuristics::compute_headroom_adjustment() { + // The trigger threshold represents mutator available - "head room". + // We plan for GC to finish before the amount of allocated memory exceeds trigger threshold. This is the same as saying we + // intend to finish GC before the amount of available memory is less than the allocation headroom. Headroom is the planned + // safety buffer to allow a small amount of additional allocation to take place in case we were overly optimistic in delaying + // our trigger. + size_t capacity = ShenandoahHeap::heap()->soft_max_capacity(); + size_t spike_headroom = capacity / 100 * ShenandoahAllocSpikeFactor; + size_t penalties = capacity / 100 * _gc_time_penalties; + _headroom_adjustment = spike_headroom + penalties; +} + +void ShenandoahAdaptiveHeuristics::start_idle_span() { + compute_headroom_adjustment(); +} + +void ShenandoahAdaptiveHeuristics::adjust_penalty(intx step) { + ShenandoahHeuristics::adjust_penalty(step); +} void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, RegionData* data, size_t size, @@ -76,8 +158,8 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand // The logic for cset selection in adaptive is as follows: // // 1. We cannot get cset larger than available free space. Otherwise we guarantee OOME - // during evacuation, and thus guarantee full GC. In practice, we also want to let - // application to allocate something. This is why we limit CSet to some fraction of + // during evacuation, and thus guarantee full GC. In practice, we also want to let the + // application allocate during concurrent GC. This is why we limit CSet to some fraction of // available space. In non-overloaded heap, max_cset would contain all plausible candidates // over garbage threshold. // @@ -108,6 +190,7 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand size_t cur_cset = 0; size_t cur_garbage = 0; + // Regions are sorted in order of decreasing garbage for (size_t idx = 0; idx < size; idx++) { ShenandoahHeapRegion* r = data[idx].get_region(); @@ -126,6 +209,88 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand } } +void ShenandoahAdaptiveHeuristics::add_degenerated_gc_time(double timestamp, double gc_time) { + // Conservatively add sample into linear model If this time is above the predicted concurrent gc time + if (predict_gc_time(timestamp) < gc_time) { + add_gc_time(timestamp, gc_time); + } +} + +void ShenandoahAdaptiveHeuristics::add_gc_time(double timestamp, double gc_time) { + // Update best-fit linear predictor of GC time + uint index = (_gc_time_first_sample_index + _gc_time_num_samples) % GC_TIME_SAMPLE_SIZE; + if (_gc_time_num_samples == GC_TIME_SAMPLE_SIZE) { + _gc_time_sum_of_timestamps -= _gc_time_timestamps[index]; + _gc_time_sum_of_samples -= _gc_time_samples[index]; + _gc_time_sum_of_xy -= _gc_time_xy[index]; + _gc_time_sum_of_xx -= _gc_time_xx[index]; + } + _gc_time_timestamps[index] = timestamp; + _gc_time_samples[index] = gc_time; + _gc_time_xy[index] = timestamp * gc_time; + _gc_time_xx[index] = timestamp * timestamp; + + _gc_time_sum_of_timestamps += _gc_time_timestamps[index]; + _gc_time_sum_of_samples += _gc_time_samples[index]; + _gc_time_sum_of_xy += _gc_time_xy[index]; + _gc_time_sum_of_xx += _gc_time_xx[index]; + + if (_gc_time_num_samples < GC_TIME_SAMPLE_SIZE) { + _gc_time_num_samples++; + } else { + _gc_time_first_sample_index = (_gc_time_first_sample_index + 1) % GC_TIME_SAMPLE_SIZE; + } + + if (_gc_time_num_samples == 1) { + // The predictor is constant (horizontal line) + _gc_time_m = 0; + _gc_time_b = gc_time; + _gc_time_sd = 0.0; + } else if (_gc_time_num_samples == 2) { + // Two points define a line + double delta_y = gc_time - _gc_time_samples[_gc_time_first_sample_index]; + double delta_x = timestamp - _gc_time_timestamps[_gc_time_first_sample_index]; + _gc_time_m = delta_y / delta_x; + + // y = mx + b + // so b = y0 - mx0 + _gc_time_b = gc_time - _gc_time_m * timestamp; + _gc_time_sd = 0.0; + } else { + _gc_time_m = ((_gc_time_num_samples * _gc_time_sum_of_xy - _gc_time_sum_of_timestamps * _gc_time_sum_of_samples) / + (_gc_time_num_samples * _gc_time_sum_of_xx - _gc_time_sum_of_timestamps * _gc_time_sum_of_timestamps)); + _gc_time_b = (_gc_time_sum_of_samples - _gc_time_m * _gc_time_sum_of_timestamps) / _gc_time_num_samples; + double sum_of_squared_deviations = 0.0; + for (size_t i = 0; i < _gc_time_num_samples; i++) { + uint index = (_gc_time_first_sample_index + i) % GC_TIME_SAMPLE_SIZE; + double x = _gc_time_timestamps[index]; + double predicted_y = _gc_time_m * x + _gc_time_b; + double deviation = predicted_y - _gc_time_samples[index]; + sum_of_squared_deviations += deviation * deviation; + } + _gc_time_sd = sqrt(sum_of_squared_deviations / _gc_time_num_samples); + } +} + +double ShenandoahAdaptiveHeuristics::predict_gc_time(double timestamp_at_start) { + return _gc_time_m * timestamp_at_start + _gc_time_b + _gc_time_sd * _margin_of_error_sd;; +} + +void ShenandoahAdaptiveHeuristics::add_rate_to_acceleration_history(double timestamp, double rate) { + uint new_sample_index = + (_spike_acceleration_first_sample_index + _spike_acceleration_num_samples) % _spike_acceleration_buffer_size; + _spike_acceleration_rate_timestamps[new_sample_index] = timestamp; + _spike_acceleration_rate_samples[new_sample_index] = rate; + if (_spike_acceleration_num_samples == _spike_acceleration_buffer_size) { + _spike_acceleration_first_sample_index++; + if (_spike_acceleration_first_sample_index == _spike_acceleration_buffer_size) { + _spike_acceleration_first_sample_index = 0; + } + } else { + _spike_acceleration_num_samples++; + } +} + void ShenandoahAdaptiveHeuristics::record_cycle_start() { ShenandoahHeuristics::record_cycle_start(); _allocation_rate.allocation_counter_reset(); @@ -133,6 +298,10 @@ void ShenandoahAdaptiveHeuristics::record_cycle_start() { void ShenandoahAdaptiveHeuristics::record_success_concurrent() { ShenandoahHeuristics::record_success_concurrent(); + double now = os::elapsedTime(); + + // Should we not add GC time if this was an abbreviated cycle? + add_gc_time(_cycle_start, elapsed_cycle_time()); size_t available = _space_info->available(); @@ -185,6 +354,7 @@ void ShenandoahAdaptiveHeuristics::record_success_concurrent() { void ShenandoahAdaptiveHeuristics::record_degenerated() { ShenandoahHeuristics::record_degenerated(); + add_degenerated_gc_time(_precursor_cycle_start, elapsed_degenerated_cycle_time()); // Adjust both trigger's parameters in the case of a degenerated GC because // either of them should have triggered earlier to avoid this case. adjust_margin_of_error(DEGENERATE_PENALTY_SD); @@ -236,6 +406,24 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { size_t available = _space_info->soft_mutator_available(); size_t allocated = _space_info->bytes_allocated_since_gc_start(); + double avg_cycle_time = 0; + double avg_alloc_rate = 0; + double now = get_most_recent_wake_time(); + size_t allocatable_words = this->allocatable(available); + double predicted_future_accelerated_gc_time = 0.0; + size_t allocated_bytes_since_last_sample = 0; + double instantaneous_rate_words_per_second = 0.0; + size_t consumption_accelerated = 0; + double acceleration = 0.0; + double current_rate_by_acceleration = 0.0; + size_t min_threshold = min_free_threshold(); + double predicted_future_gc_time = 0; + double future_planned_gc_time = 0; + bool future_planned_gc_time_is_average = false; + double avg_time_to_deplete_available = 0.0; + bool is_spiking = false; + double spike_time_to_deplete_available = 0.0; + log_debug(gc, ergo)("should_start_gc calculation: available: " PROPERFMT ", soft_max_capacity: " PROPERFMT ", " "allocated_since_gc_start: " PROPERFMT, PROPERFMTARGS(available), PROPERFMTARGS(capacity), PROPERFMTARGS(allocated)); @@ -250,7 +438,6 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { _last_trigger = OTHER; - size_t min_threshold = min_free_threshold(); if (available < min_threshold) { log_trigger("Free (Soft) (" PROPERFMT ") is below minimum threshold (" PROPERFMT ")", PROPERFMTARGS(available), PROPERFMTARGS(min_threshold)); @@ -271,55 +458,227 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { return true; } } - // Check if allocation headroom is still okay. This also factors in: - // 1. Some space to absorb allocation spikes (ShenandoahAllocSpikeFactor) - // 2. Accumulated penalties from Degenerated and Full GC - size_t allocation_headroom = available; - size_t spike_headroom = capacity / 100 * ShenandoahAllocSpikeFactor; - size_t penalties = capacity / 100 * _gc_time_penalties; + // The test (3 * allocated > available) below is intended to prevent triggers from firing so quickly that there + // has not been sufficient time to create garbage that can be reclaimed during the triggered GC cycle. If we trigger before + // garbage has been created, the concurrent GC will find no garbage. This has been observed to result in degens which + // experience OOM during evac or that experience "bad progress", both of which escalate to Full GC. Note that garbage that + // was allocated following the start of the current GC cycle cannot be reclaimed in this GC cycle. Here is the derivation + // of the expression: + // + // Let R (runway) represent the total amount of memory that can be allocated following the start of GC(N). The runway + // represents memory available at the start of the current GC plus garbage reclaimed by the current GC. In a balanced, + // fully utilized configuration, we will be starting each new GC cycle immediately following completion of the preceding + // GC cycle. In this configuration, we would expect half of R to be consumed during concurrent cycle GC(N) and half + // to be consumed during concurrent GC(N+1). + // + // Assume we want to delay GC trigger until: A/V > 0.33 + // This is equivalent to enforcing that: A > 0.33V + // which is: 3A > V + // Since A+V equals R, we have: A + 3A > A + V = R + // which is to say that: A > R/4 + // + // Postponing the trigger until at least 1/4 of the runway has been consumed helps to improve the efficiency of the + // triggered GC. Under heavy steady state workload, this delay condition generally has no effect: if the allocation + // runway is divided "equally" between the current GC and the next GC, then at any potential trigger point (which cannot + // happen any sooner than completion of the first GC), it is already the case that roughly A > R/2. + if (3 * allocated <= available) { + // Even though we will not issue an adaptive trigger unless a minimum threshold of memory has been allocated, + // we still allow more generic triggers, such as guaranteed GC intervals, to act. + return ShenandoahHeuristics::should_start_gc(); + } - allocation_headroom -= MIN2(allocation_headroom, spike_headroom); - allocation_headroom -= MIN2(allocation_headroom, penalties); + avg_cycle_time = _gc_cycle_time_history->davg() + (_margin_of_error_sd * _gc_cycle_time_history->dsd()); + avg_alloc_rate = _allocation_rate.upper_bound(_margin_of_error_sd); + if ((now - _previous_acceleration_sample_timestamp) >= (ShenandoahAccelerationSamplePeriod / 1000.0)) { + predicted_future_accelerated_gc_time = + predict_gc_time(now + MAX2(get_planned_sleep_interval(), ShenandoahAccelerationSamplePeriod / 1000.0)); + double future_accelerated_planned_gc_time; + bool future_accelerated_planned_gc_time_is_average; + if (predicted_future_accelerated_gc_time > avg_cycle_time) { + future_accelerated_planned_gc_time = predicted_future_accelerated_gc_time; + future_accelerated_planned_gc_time_is_average = false; + } else { + future_accelerated_planned_gc_time = avg_cycle_time; + future_accelerated_planned_gc_time_is_average = true; + } + allocated_bytes_since_last_sample = _free_set->get_bytes_allocated_since_previous_sample(); + instantaneous_rate_words_per_second = + (allocated_bytes_since_last_sample / HeapWordSize) / (now - _previous_acceleration_sample_timestamp); - double avg_cycle_time = _gc_cycle_time_history->davg() + (_margin_of_error_sd * _gc_cycle_time_history->dsd()); - double avg_alloc_rate = _allocation_rate.upper_bound(_margin_of_error_sd); + _previous_acceleration_sample_timestamp = now; + add_rate_to_acceleration_history(now, instantaneous_rate_words_per_second); + current_rate_by_acceleration = instantaneous_rate_words_per_second; + consumption_accelerated = + accelerated_consumption(acceleration, current_rate_by_acceleration, avg_alloc_rate / HeapWordSize, + (ShenandoahAccelerationSamplePeriod / 1000.0) + future_accelerated_planned_gc_time); - log_debug(gc)("average GC time: %.2f ms, allocation rate: %.0f %s/s", - avg_cycle_time * 1000, byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate)); - if (avg_cycle_time * avg_alloc_rate > allocation_headroom) { - log_trigger("Average GC time (%.2f ms) is above the time for average allocation rate (%.0f %sB/s)" - " to deplete free headroom (%zu%s) (margin of error = %.2f)", - avg_cycle_time * 1000, - byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate), - byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom), - _margin_of_error_sd); - log_info(gc, ergo)("Free headroom: %zu%s (free) - %zu%s (spike) - %zu%s (penalties) = %zu%s", - byte_size_in_proper_unit(available), proper_unit_for_byte_size(available), - byte_size_in_proper_unit(spike_headroom), proper_unit_for_byte_size(spike_headroom), - byte_size_in_proper_unit(penalties), proper_unit_for_byte_size(penalties), - byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom)); + // Note that even a single thread that wakes up and begins to allocate excessively can manifest as accelerating allocation + // rate. This thread will initially allocate a TLAB of minimum size. Then it will allocate a TLAB twice as big a bit later, + // and then twice as big again after another short delay. When a phase change causes many threads to increase their + // allocation behavior, this effect is multiplied, and compounded by jitter in the times that individual threads experience + // the phase change. + // + // The following trace represents an actual workload, with allocation rates sampled at 10 Hz, the default behavior before + // introduction of accelerated allocation rate detection. Though the allocation rate is seen to be increasing at times + // 101.907 and 102.007 and 102.108, the newly sampled allocation rate is not enough to trigger GC because the headroom is + // still quite large. In fact, GC is not triggered until time 102.409s, and this GC degenerates. + // + // Sample Time (s) Allocation Rate (MB/s) Headroom (GB) + // 101.807 0.0 26.93 + // <--- accelerated spike can trigger here, around time 101.9s + // 101.907 477.6 26.85 + // 102.007 3,206.0 26.35 + // 102.108 23,797.8 24.19 + // 102.208 24,164.5 21.83 + // 102.309 23,965.0 19.47 + // 102.409 24,624.35 17.05 <--- without accelerated rate detection, we trigger here + // + // Though the above measurements are from actual workload, the following details regarding sampled allocation rates at 3ms + // period were not measured directly for this run-time sample. These are hypothetical, though they represent a plausible + // result that correlates with the actual measurements. + // + // For most of the 100 ms time span that precedes the sample at 101.907, the allocation rate still remains at zero. The phase + // change that causes increasing allocations occurs near the end ot this time segment. When sampled with a 3 ms period, + // acceration of allocation can be triggered at approximately time 101.88s. + // + // In the default configuration, accelerated allocation rate is detected by examining a sequence of 8 allocation rate samples. + // + // Even a single allocation rate sample above the norm can be interpreted as acceleration of allocation rate. For example, the + // the best-fit line for the following samples has an acceleration rate of 3,553.3 MB/s/s. This is not enough to trigger GC, + // especially given the abundance of Headroom at this moment in time. + // + // TimeStamp (s) Alloc rate (MB/s) + // 101.857 0 + // 101.860 0 + // 101.863 0 + // 101.866 0 + // 101.869 53.3 + // + // At the next sample time, we will compute a slightly higher acceration, 9,150 MB/s/s. This is also insufficient to trigger + // GC. + // + // TimeStamp (s) Alloc rate (MB/s) + // 101.860 0 + // 101.863 0 + // 101.866 0 + // 101.869 53.3 + // 101.872 110.6 + // + // Eventually, we will observe a full history of accelerating rate samples, computing acceleration of 18,500 MB/s/s. This will + // trigger GC over 500 ms earlier than was previously possible. + // + // TimeStamp (s) Alloc rate (MB/s) + // 101.866 0 + // 101.869 53.3 + // 101.872 110.6 + // 101.875 165.9 + // 101.878 221.2 + // + // The accelerated rate heuristic is based on the following idea: + // + // Assume allocation rate is accelerating at a constant rate. If we postpone the spike trigger until the subsequent + // sample point, will there be enough memory to satisfy allocations that occur during the anticipated concurrent GC + // cycle? If not, we should trigger right now. + // + // Outline of this heuristic triggering technique: + // + // 1. We remember the N (e.g. N=3) most recent samples of spike allocation rate r0, r1, r2 samples at t0, t1, and t2 + // 2. if r1 < r0 or r2 < r1, approximate Acceleration = 0.0, Rate = Average(r0, r1, r2) + // 3. Otherwise, use least squares method to compute best-fit line of rate vs time + // 4. The slope of this line represents Acceleration. The y-intercept of this line represents "initial rate" + // 5. Use r2 to rrpresent CurrentRate + // 6. Use Consumption = CurrentRate * GCTime + 1/2 * Acceleration * GCTime * GCTime + // (See High School physics discussions on constant acceleration: D = v0 * t + 1/2 * a * t^2) + // 7. if Consumption exceeds headroom, trigger now + // + // Though larger sample size may improve quality of predictor, it also delays trigger response. Smaller sample sizes + // are more susceptible to false triggers based on random noise. The default configuration uses a sample size of 8 and + // a sample period of roughly 15 ms, spanning approximately 120 ms of execution. + if (consumption_accelerated > allocatable_words) { + size_t size_t_alloc_rate = (size_t) current_rate_by_acceleration * HeapWordSize; + if (acceleration > 0) { + size_t size_t_acceleration = (size_t) acceleration * HeapWordSize; + log_trigger("Accelerated consumption (" PROPERFMT ") exceeds free headroom (" PROPERFMT ") at " + "current rate (" PROPERFMT "/s) with acceleration (" PROPERFMT "/s/s) for planned %s GC time (%.2f ms)", + PROPERFMTARGS(consumption_accelerated * HeapWordSize), + PROPERFMTARGS(allocatable_words * HeapWordSize), + PROPERFMTARGS(size_t_alloc_rate), + PROPERFMTARGS(size_t_acceleration), + future_accelerated_planned_gc_time_is_average? "(from average)": "(by linear prediction)", + future_accelerated_planned_gc_time * 1000); + } else { + log_trigger("Momentary spike consumption (" PROPERFMT ") exceeds free headroom (" PROPERFMT ") at " + "current rate (" PROPERFMT "/s) for planned %s GC time (%.2f ms) (spike threshold = %.2f)", + PROPERFMTARGS(consumption_accelerated * HeapWordSize), + PROPERFMTARGS(allocatable_words * HeapWordSize), + PROPERFMTARGS(size_t_alloc_rate), + future_accelerated_planned_gc_time_is_average? "(from average)": "(by linear prediction)", + future_accelerated_planned_gc_time * 1000, _spike_threshold_sd); + + + } + _spike_acceleration_num_samples = 0; + _spike_acceleration_first_sample_index = 0; + + // Count this as a form of RATE trigger for purposes of adjusting heuristic triggering configuration because this + // trigger is influenced more by margin_of_error_sd than by spike_threshold_sd. + accept_trigger_with_type(RATE); + return true; + } + } + + // Suppose we don't trigger now, but decide to trigger in the next regulator cycle. What will be the GC time then? + predicted_future_gc_time = predict_gc_time(now + get_planned_sleep_interval()); + if (predicted_future_gc_time > avg_cycle_time) { + future_planned_gc_time = predicted_future_gc_time; + future_planned_gc_time_is_average = false; + } else { + future_planned_gc_time = avg_cycle_time; + future_planned_gc_time_is_average = true; + } + + log_debug(gc)("%s: average GC time: %.2f ms, predicted GC time: %.2f ms, allocation rate: %.0f %s/s", + _space_info->name(), avg_cycle_time * 1000, predicted_future_gc_time * 1000, + byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate)); + size_t allocatable_bytes = allocatable_words * HeapWordSize; + avg_time_to_deplete_available = allocatable_bytes / avg_alloc_rate; + + if (future_planned_gc_time > avg_time_to_deplete_available) { + log_trigger("%s GC time (%.2f ms) is above the time for average allocation rate (%.0f %sB/s)" + " to deplete free headroom (%zu%s) (margin of error = %.2f)", + future_planned_gc_time_is_average? "Average": "Linear prediction of", future_planned_gc_time * 1000, + byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate), + byte_size_in_proper_unit(allocatable_bytes), proper_unit_for_byte_size(allocatable_bytes), + _margin_of_error_sd); + + size_t spike_headroom = capacity / 100 * ShenandoahAllocSpikeFactor; + size_t penalties = capacity / 100 * _gc_time_penalties; + size_t allocation_headroom = available; + allocation_headroom -= MIN2(allocation_headroom, spike_headroom); + allocation_headroom -= MIN2(allocation_headroom, penalties); + log_info(gc, ergo)("Free headroom: " PROPERFMT " (free) - " PROPERFMT "(spike) - " PROPERFMT " (penalties) = " PROPERFMT, + PROPERFMTARGS(available), + PROPERFMTARGS(spike_headroom), + PROPERFMTARGS(penalties), + PROPERFMTARGS(allocation_headroom)); accept_trigger_with_type(RATE); return true; } - bool is_spiking = _allocation_rate.is_spiking(rate, _spike_threshold_sd); - if (is_spiking && avg_cycle_time > allocation_headroom / rate) { - log_trigger("Average GC time (%.2f ms) is above the time for instantaneous allocation rate (%.0f %sB/s) to deplete free headroom (%zu%s) (spike threshold = %.2f)", - avg_cycle_time * 1000, - byte_size_in_proper_unit(rate), proper_unit_for_byte_size(rate), - byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom), - _spike_threshold_sd); + is_spiking = _allocation_rate.is_spiking(rate, _spike_threshold_sd); + spike_time_to_deplete_available = (rate == 0)? 0: allocatable_bytes / rate; + if (is_spiking && (rate != 0) && (future_planned_gc_time > spike_time_to_deplete_available)) { + log_trigger("%s GC time (%.2f ms) is above the time for instantaneous allocation rate (%.0f %sB/s)" + " to deplete free headroom (%zu%s) (spike threshold = %.2f)", + future_planned_gc_time_is_average? "Average": "Linear prediction of", future_planned_gc_time * 1000, + byte_size_in_proper_unit(rate), proper_unit_for_byte_size(rate), + byte_size_in_proper_unit(allocatable_bytes), proper_unit_for_byte_size(allocatable_bytes), + _spike_threshold_sd); accept_trigger_with_type(SPIKE); return true; } - - if (ShenandoahHeuristics::should_start_gc()) { - _start_gc_is_pending = true; - return true; - } else { - return false; - } + return ShenandoahHeuristics::should_start_gc(); } void ShenandoahAdaptiveHeuristics::adjust_last_trigger_parameters(double amount) { @@ -352,6 +711,112 @@ size_t ShenandoahAdaptiveHeuristics::min_free_threshold() { return ShenandoahHeap::heap()->soft_max_capacity() / 100 * ShenandoahMinFreeThreshold; } +// This is called each time a new rate sample has been gathered, as governed by ShenandoahAccelerationSamplePeriod. +// Unlike traditional calculation of average allocation rate, there is no adjustment for standard deviation of the +// accelerated rate prediction. +size_t ShenandoahAdaptiveHeuristics::accelerated_consumption(double& acceleration, double& current_rate, + double avg_alloc_rate_words_per_second, + double predicted_cycle_time) const +{ + double *x_array = (double *) alloca(ShenandoahRateAccelerationSampleSize * sizeof(double)); + double *y_array = (double *) alloca(ShenandoahRateAccelerationSampleSize * sizeof(double)); + double x_sum = 0.0; + double y_sum = 0.0; + + assert(_spike_acceleration_num_samples > 0, "At minimum, we should have sample from this period"); + + double weighted_average_alloc; + if (_spike_acceleration_num_samples >= ShenandoahRateAccelerationSampleSize) { + double weighted_y_sum = 0; + double total_weight = 0; + double previous_x = 0; + uint delta = _spike_acceleration_num_samples - ShenandoahRateAccelerationSampleSize; + for (uint i = 0; i < ShenandoahRateAccelerationSampleSize; i++) { + uint index = (_spike_acceleration_first_sample_index + delta + i) % _spike_acceleration_buffer_size; + x_array[i] = _spike_acceleration_rate_timestamps[index]; + x_sum += x_array[i]; + y_array[i] = _spike_acceleration_rate_samples[index]; + if (i > 0) { + // first sample not included in weighted average because it has no weight. + double sample_weight = x_array[i] - x_array[i-1]; + weighted_y_sum = y_array[i] * sample_weight; + total_weight += sample_weight; + } + y_sum += y_array[i]; + } + weighted_average_alloc = (total_weight > 0)? weighted_y_sum / total_weight: 0; + } else { + weighted_average_alloc = 0; + } + + double momentary_rate; + if (_spike_acceleration_num_samples > ShenandoahMomentaryAllocationRateSpikeSampleSize) { + // Num samples must be strictly greater than sample size, because we need one extra sample to compute rate and weights + // In this context, the weight of a y value (an allocation rate) is the duration for which this allocation rate was + // active (the time since previous y value was reported). An allocation rate measured over a span of 300 ms (e.g. during + // concurrent GC) has much more "weight" than an allocation rate measured over a span of 15 s. + double weighted_y_sum = 0; + double total_weight = 0; + double sum_for_average = 0.0; + uint delta = _spike_acceleration_num_samples - ShenandoahMomentaryAllocationRateSpikeSampleSize; + for (uint i = 0; i < ShenandoahMomentaryAllocationRateSpikeSampleSize; i++) { + uint sample_index = (_spike_acceleration_first_sample_index + delta + i) % _spike_acceleration_buffer_size; + uint preceding_index = (sample_index == 0)? _spike_acceleration_buffer_size - 1: sample_index - 1; + double sample_weight = (_spike_acceleration_rate_timestamps[sample_index] + - _spike_acceleration_rate_timestamps[preceding_index]); + weighted_y_sum += _spike_acceleration_rate_samples[sample_index] * sample_weight; + total_weight += sample_weight; + } + momentary_rate = weighted_y_sum / total_weight; + bool is_spiking = _allocation_rate.is_spiking(momentary_rate, _spike_threshold_sd); + if (!is_spiking) { + // Disable momentary spike trigger unless allocation rate delta from average exceeds sd + momentary_rate = 0.0; + } + } else { + momentary_rate = 0.0; + } + + // By default, use momentary_rate for current rate and zero acceleration. Overwrite iff best-fit line has positive slope. + current_rate = momentary_rate; + acceleration = 0.0; + if ((_spike_acceleration_num_samples >= ShenandoahRateAccelerationSampleSize) + && (weighted_average_alloc >= avg_alloc_rate_words_per_second)) { + // If the average rate across the acceleration samples is below the overall average, this sample is not eligible to + // represent acceleration of allocation rate. We may just be catching up with allocations after a lull. + + double *xy_array = (double *) alloca(ShenandoahRateAccelerationSampleSize * sizeof(double)); + double *x2_array = (double *) alloca(ShenandoahRateAccelerationSampleSize * sizeof(double)); + double xy_sum = 0.0; + double x2_sum = 0.0; + for (uint i = 0; i < ShenandoahRateAccelerationSampleSize; i++) { + xy_array[i] = x_array[i] * y_array[i]; + xy_sum += xy_array[i]; + x2_array[i] = x_array[i] * x_array[i]; + x2_sum += x2_array[i]; + } + // Find the best-fit least-squares linear representation of rate vs time + double m; /* slope */ + double b; /* y-intercept */ + + m = ((ShenandoahRateAccelerationSampleSize * xy_sum - x_sum * y_sum) + / (ShenandoahRateAccelerationSampleSize * x2_sum - x_sum * x_sum)); + b = (y_sum - m * x_sum) / ShenandoahRateAccelerationSampleSize; + + if (m > 0) { + double proposed_current_rate = m * x_array[ShenandoahRateAccelerationSampleSize - 1] + b; + acceleration = m; + current_rate = proposed_current_rate; + } + // else, leave current_rate = momentary_rate, acceleration = 0 + } + // and here also, leave current_rate = momentary_rate, acceleration = 0 + + double time_delta = get_planned_sleep_interval() + predicted_cycle_time; + size_t words_to_be_consumed = (size_t) (current_rate * time_delta + 0.5 * acceleration * time_delta * time_delta); + return words_to_be_consumed; +} + ShenandoahAllocationRate::ShenandoahAllocationRate() : _last_sample_time(os::elapsedTime()), _last_sample_value(0), @@ -363,7 +828,7 @@ ShenandoahAllocationRate::ShenandoahAllocationRate() : double ShenandoahAllocationRate::force_sample(size_t allocated, size_t &unaccounted_bytes_allocated) { const double MinSampleTime = 0.002; // Do not sample if time since last update is less than 2 ms double now = os::elapsedTime(); - double time_since_last_update = now -_last_sample_time; + double time_since_last_update = now - _last_sample_time; if (time_since_last_update < MinSampleTime) { unaccounted_bytes_allocated = allocated - _last_sample_value; _last_sample_value = 0; @@ -412,8 +877,10 @@ bool ShenandoahAllocationRate::is_spiking(double rate, double threshold) const { double sd = _rate.sd(); if (sd > 0) { - // There is a small chance that that rate has already been sampled, but it - // seems not to matter in practice. + // There is a small chance that that rate has already been sampled, but it seems not to matter in practice. + // Note that z_score reports how close the rate is to the average. A value between -1 and 1 means we are within one + // standard deviation. A value between -3 and +3 means we are within 3 standard deviations. We only check for z_score + // greater than threshold because we are looking for an allocation spike which is greater than the mean. double z_score = (rate - _rate.avg()) / sd; if (z_score > threshold) { return true; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp index 9b7824a50d7..c761f2a82f3 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp @@ -27,7 +27,9 @@ #define SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHADAPTIVEHEURISTICS_HPP #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" +#include "gc/shenandoah/shenandoahRegulatorThread.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "memory/allocation.hpp" #include "utilities/numberSeq.hpp" @@ -108,6 +110,26 @@ public: virtual ~ShenandoahAdaptiveHeuristics(); + virtual void initialize() override; + + virtual void post_initialize() override; + + virtual void adjust_penalty(intx step) override; + + // At the end of GC(N), we idle GC until necessary to start the next GC. Compute the threshold of memory that can be allocated + // before we need to start the next GC. + void start_idle_span() override; + + // Having observed a new allocation rate sample, add this to the acceleration history so that we can determine if allocation + // rate is accelerating. + void add_rate_to_acceleration_history(double timestamp, double rate); + + // Compute and return the current allocation rate, the current rate of acceleration, and the amount of memory that we expect + // to consume if we start GC right now and gc takes predicted_cycle_time to complete. + size_t accelerated_consumption(double& acceleration, double& current_rate, + double avg_rate_words_per_sec, double predicted_cycle_time) const; + + void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, RegionData* data, size_t size, size_t actual_free) override; @@ -136,6 +158,8 @@ public: const static double LOWEST_EXPECTED_AVAILABLE_AT_END; const static double HIGHEST_EXPECTED_AVAILABLE_AT_END; + const static size_t GC_TIME_SAMPLE_SIZE; + friend class ShenandoahAllocationRate; // Used to record the last trigger that signaled to start a GC. @@ -150,9 +174,19 @@ public: void adjust_margin_of_error(double amount); void adjust_spike_threshold(double amount); + // Returns number of words that can be allocated before we need to trigger next GC, given available in bytes. + inline size_t allocatable(size_t available) const { + return (available > _headroom_adjustment)? (available - _headroom_adjustment) / HeapWordSize: 0; + } + protected: ShenandoahAllocationRate _allocation_rate; + // Invocations of should_start_gc() happen approximately once per ms. Queries of allocation rate only happen if a + // a certain amount of time has passed since the previous query. + size_t _allocated_at_previous_query; + double _time_of_previous_allocation_query; + // The margin of error expressed in standard deviations to add to our // average cycle time and allocation rate. As this value increases we // tend to overestimate the rate at which mutators will deplete the @@ -179,6 +213,48 @@ protected: // source of feedback to adjust trigger parameters. TruncatedSeq _available; + ShenandoahFreeSet* _free_set; + + // This represents the time at which the allocation rate was most recently sampled for the purpose of detecting acceleration. + double _previous_acceleration_sample_timestamp; + size_t _total_allocations_at_start_of_idle; + + // bytes of headroom at which we should trigger GC + size_t _headroom_adjustment; + + // Keep track of GC_TIME_SAMPLE_SIZE most recent concurrent GC cycle times + uint _gc_time_first_sample_index; + uint _gc_time_num_samples; + double* const _gc_time_timestamps; + double* const _gc_time_samples; + double* const _gc_time_xy; // timestamp * sample + double* const _gc_time_xx; // timestamp squared + double _gc_time_sum_of_timestamps; + double _gc_time_sum_of_samples; + double _gc_time_sum_of_xy; + double _gc_time_sum_of_xx; + + double _gc_time_m; // slope + double _gc_time_b; // y-intercept + double _gc_time_sd; // sd on deviance from prediction + + // In preparation for a span during which GC will be idle, compute the headroom adjustment that will be used to + // detect when GC needs to trigger. + void compute_headroom_adjustment() override; + + void add_gc_time(double timestamp_at_start, double duration); + void add_degenerated_gc_time(double timestamp_at_start, double duration); + double predict_gc_time(double timestamp_at_start); + + // Keep track of SPIKE_ACCELERATION_SAMPLE_SIZE most recent spike allocation rate measurements. Note that it is + // typical to experience a small spike following end of GC cycle, as mutator threads refresh their TLABs. But + // there is generally an abundance of memory at this time as well, so this will not generally trigger GC. + uint _spike_acceleration_buffer_size; + uint _spike_acceleration_first_sample_index; + uint _spike_acceleration_num_samples; + double* const _spike_acceleration_rate_samples; // holds rates in words/second + double* const _spike_acceleration_rate_timestamps; + // A conservative minimum threshold of free space that we'll try to maintain when possible. // For example, we might trigger a concurrent gc if we are likely to drop below // this threshold, or we might consider this when dynamically resizing generations diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index 029b917deab..f3d31b8d0e1 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -52,6 +52,12 @@ static int compare_by_aged_live(AgedRegionData a, AgedRegionData b) { return 0; } +void ShenandoahGenerationalHeuristics::post_initialize() { + ShenandoahHeuristics::post_initialize(); + _free_set = ShenandoahHeap::heap()->free_set(); + compute_headroom_adjustment(); +} + inline void assert_no_in_place_promotions() { #ifdef ASSERT class ShenandoahNoInPlacePromotions : public ShenandoahHeapRegionClosure { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp index 74d657feab7..da883d0d26f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp @@ -49,6 +49,8 @@ public: void choose_collection_set(ShenandoahCollectionSet* collection_set) override; + virtual void post_initialize() override; + private: // Compute evacuation budgets prior to choosing collection set. void compute_evacuation_budgets(ShenandoahHeap* const heap); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 8fc744112bf..603e00c401d 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -46,13 +46,16 @@ int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) { } ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) : + _most_recent_trigger_evaluation_time(os::elapsedTime()), + _most_recent_planned_sleep_interval(0.0), _start_gc_is_pending(false), _declined_trigger_count(0), _most_recent_declined_trigger_count(0), _space_info(space_info), _region_data(nullptr), _guaranteed_gc_interval(0), - _cycle_start(os::elapsedTime()), + _precursor_cycle_start(os::elapsedTime()), + _cycle_start(_precursor_cycle_start), _last_cycle_end(0), _gc_times_learned(0), _gc_time_penalties(0), @@ -156,6 +159,19 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec collection_set->summarize(total_garbage, immediate_garbage, immediate_regions); } +void ShenandoahHeuristics::start_idle_span() { + // do nothing +} + +void ShenandoahHeuristics::record_degenerated_cycle_start(bool out_of_cycle) { + if (out_of_cycle) { + _precursor_cycle_start = _cycle_start = os::elapsedTime(); + } else { + _precursor_cycle_start = _cycle_start; + _cycle_start = os::elapsedTime(); + } +} + void ShenandoahHeuristics::record_cycle_start() { _cycle_start = os::elapsedTime(); } @@ -197,7 +213,6 @@ bool ShenandoahHeuristics::should_degenerate_cycle() { void ShenandoahHeuristics::adjust_penalty(intx step) { assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100, "In range before adjustment: %zd", _gc_time_penalties); - if ((_most_recent_declined_trigger_count <= Penalty_Free_Declinations) && (step > 0)) { // Don't penalize if heuristics are not responsible for a negative outcome. Allow Penalty_Free_Declinations following // previous GC for self calibration without penalty. @@ -274,6 +289,17 @@ void ShenandoahHeuristics::initialize() { // Nothing to do by default. } +void ShenandoahHeuristics::post_initialize() { + // Nothing to do by default. +} + double ShenandoahHeuristics::elapsed_cycle_time() const { return os::elapsedTime() - _cycle_start; } + + +// Includes the time spent in abandoned concurrent GC cycle that may have triggered this degenerated cycle. +double ShenandoahHeuristics::elapsed_degenerated_cycle_time() const { + double now = os::elapsedTime(); + return now - _precursor_cycle_start; +} diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp index 633c4e87126..5bfba4f52d5 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.hpp @@ -78,6 +78,10 @@ class ShenandoahHeuristics : public CHeapObj { }; #endif +private: + double _most_recent_trigger_evaluation_time; + double _most_recent_planned_sleep_interval; + protected: static const uint Moving_Average_Samples = 10; // Number of samples to store in moving averages @@ -85,14 +89,13 @@ protected: size_t _declined_trigger_count; // This counts how many times since previous GC finished that this // heuristic has answered false to should_start_gc(). size_t _most_recent_declined_trigger_count; - ; // This represents the value of _declined_trigger_count as captured at the + // This represents the value of _declined_trigger_count as captured at the // moment the most recent GC effort was triggered. In case the most recent // concurrent GC effort degenerates, the value of this variable allows us to // differentiate between degeneration because heuristic was overly optimistic // in delaying the trigger vs. degeneration for other reasons (such as the // most recent GC triggered "immediately" after previous GC finished, but the // free headroom has already been depleted). - class RegionData { private: ShenandoahHeapRegion* _region; @@ -103,6 +106,7 @@ protected: #ifdef ASSERT UnionTag _union_tag; #endif + public: inline void clear() { @@ -171,6 +175,7 @@ protected: size_t _guaranteed_gc_interval; + double _precursor_cycle_start; double _cycle_start; double _last_cycle_end; @@ -188,7 +193,7 @@ protected: RegionData* data, size_t data_size, size_t free) = 0; - void adjust_penalty(intx step); + virtual void adjust_penalty(intx step); inline void accept_trigger() { _most_recent_declined_trigger_count = _declined_trigger_count; @@ -200,6 +205,14 @@ protected: _declined_trigger_count++; } + inline double get_most_recent_wake_time() const { + return _most_recent_trigger_evaluation_time; + } + + inline double get_planned_sleep_interval() const { + return _most_recent_planned_sleep_interval; + } + public: ShenandoahHeuristics(ShenandoahSpaceInfo* space_info); virtual ~ShenandoahHeuristics(); @@ -212,10 +225,22 @@ public: _guaranteed_gc_interval = guaranteed_gc_interval; } + virtual void start_idle_span(); + virtual void compute_headroom_adjustment() { + // Default implementation does nothing. + } + virtual void record_cycle_start(); + void record_degenerated_cycle_start(bool out_of_cycle); + virtual void record_cycle_end(); + void update_should_start_query_times(double now, double planned_sleep_interval) { + _most_recent_trigger_evaluation_time = now; + _most_recent_planned_sleep_interval = planned_sleep_interval; + } + virtual bool should_start_gc(); inline void cancel_trigger_request() { @@ -248,8 +273,10 @@ public: virtual bool is_diagnostic() = 0; virtual bool is_experimental() = 0; virtual void initialize(); + virtual void post_initialize(); double elapsed_cycle_time() const; + double elapsed_degenerated_cycle_time() const; virtual size_t force_alloc_rate_sample(size_t bytes_allocated) { // do nothing diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index beff2200d90..09508a1163f 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -137,6 +137,7 @@ bool ShenandoahYoungHeuristics::should_start_gc() { // inherited triggers have already decided to start a cycle, so no further evaluation is required if (ShenandoahAdaptiveHeuristics::should_start_gc()) { + // ShenandoahAdaptiveHeuristics::should_start_gc() has already accepted trigger, or declined it. return true; } @@ -178,7 +179,7 @@ size_t ShenandoahYoungHeuristics::bytes_of_allocation_runway_before_gc_trigger(s size_t capacity = _space_info->max_capacity(); size_t usage = _space_info->used(); size_t available = (capacity > usage)? capacity - usage: 0; - size_t allocated = _space_info->bytes_allocated_since_gc_start(); + size_t allocated = _free_set->get_bytes_allocated_since_gc_start(); size_t available_young_collected = ShenandoahHeap::heap()->collection_set()->get_young_available_bytes_collected(); size_t anticipated_available = diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 5206a0558e8..f0125c38cae 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -1215,6 +1215,7 @@ void ShenandoahConcurrentGC::op_final_update_refs() { } heap->rebuild_free_set(true /*concurrent*/); + _generation->heuristics()->start_idle_span(); { ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_update_refs_propagate_gc_state); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index bc11659c5e5..c5607421265 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -59,6 +59,7 @@ void ShenandoahControlThread::run_service() { ShenandoahCollectorPolicy* const policy = heap->shenandoah_policy(); ShenandoahHeuristics* const heuristics = heap->heuristics(); + double most_recent_wake_time = os::elapsedTime(); while (!should_terminate()) { const GCCause::Cause cancelled_cause = heap->cancelled_cause(); if (cancelled_cause == GCCause::_shenandoah_stop_vm) { @@ -222,16 +223,26 @@ void ShenandoahControlThread::run_service() { // Wait before performing the next action. If allocation happened during this wait, // we exit sooner, to let heuristics re-evaluate new conditions. If we are at idle, // back off exponentially. - const double current = os::elapsedTime(); + const double before_sleep = most_recent_wake_time; if (heap->has_changed()) { sleep = ShenandoahControlIntervalMin; - } else if ((current - last_sleep_adjust_time) * 1000 > ShenandoahControlIntervalAdjustPeriod){ + } else if ((before_sleep - last_sleep_adjust_time) * 1000 > ShenandoahControlIntervalAdjustPeriod){ sleep = MIN2(ShenandoahControlIntervalMax, MAX2(1, sleep * 2)); - last_sleep_adjust_time = current; + last_sleep_adjust_time = before_sleep; } - MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); ml.wait(sleep); + // Record a conservative estimate of the longest anticipated sleep duration until we sample again. + double planned_sleep_interval = MIN2(ShenandoahControlIntervalMax, MAX2(1, sleep * 2)) / 1000.0; + most_recent_wake_time = os::elapsedTime(); + heuristics->update_should_start_query_times(most_recent_wake_time, planned_sleep_interval); + if (LogTarget(Debug, gc, thread)::is_enabled()) { + double elapsed = most_recent_wake_time - before_sleep; + double hiccup = elapsed - double(sleep); + if (hiccup > 0.001) { + log_debug(gc, thread)("Control Thread hiccup time: %.3fs", hiccup); + } + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 99776e38bfe..8cd8a390c4a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -314,6 +314,7 @@ void ShenandoahDegenGC::op_degenerated() { if (progress) { heap->notify_gc_progress(); _generation->heuristics()->record_degenerated(); + heap->start_idle_span(); } else if (policy->should_upgrade_degenerated_gc()) { // Upgrade to full GC, register full-GC impact on heuristics. op_degenerated_futile(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 961800f20d9..c39e2e7bb79 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -287,9 +287,25 @@ void ShenandoahFreeSet::resize_old_collector_capacity(size_t regions) { // else, old generation is already appropriately sized } + void ShenandoahFreeSet::reset_bytes_allocated_since_gc_start(size_t initial_bytes_allocated) { shenandoah_assert_heaplocked(); + // Future inquiries of get_total_bytes_allocated() will return the sum of + // _total_bytes_previously_allocated and _mutator_bytes_allocated_since_gc_start. + // Since _mutator_bytes_allocated_since_gc_start does not start at zero, we subtract initial_bytes_allocated so as + // to not double count these allocated bytes. + size_t original_mutator_bytes_allocated_since_gc_start = _mutator_bytes_allocated_since_gc_start; + + // Setting _mutator_bytes_allocated_since_gc_start before _total_bytes_previously_allocated reduces the damage + // in the case that the control or regulator thread queries get_bytes_allocated_since_previous_sample() between + // the two assignments. + // + // These are not declared as volatile so the compiler or hardware may reorder the assignments. The implementation of + // get_bytes_allocated_since_previous_cycle() is robust to this possibility, as are triggering heuristics. The current + // implementation assumes we are better off to tolerate the very rare race rather than impose a synchronization penalty + // on every update and fetch. (Perhaps it would be better to make the opposite tradeoff for improved maintainability.) _mutator_bytes_allocated_since_gc_start = initial_bytes_allocated; + _total_bytes_previously_allocated += original_mutator_bytes_allocated_since_gc_start - initial_bytes_allocated; } void ShenandoahFreeSet::increase_bytes_allocated(size_t bytes) { @@ -1211,6 +1227,8 @@ inline void ShenandoahRegionPartitions::assert_bounds_sanity() { ShenandoahFreeSet::ShenandoahFreeSet(ShenandoahHeap* heap, size_t max_regions) : _heap(heap), _partitions(max_regions, this), + _total_bytes_previously_allocated(0), + _mutator_bytes_at_last_sample(0), _total_humongous_waste(0), _alloc_bias_weight(0), _total_young_used(0), @@ -1676,9 +1694,6 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah // Regardless of whether this allocation succeeded, if the remaining memory is less than PLAB:min_size(), retire this region. // Note that retire_from_partition() increases used to account for waste. - // Also, if this allocation request failed and the consumed within this region * ShenandoahEvacWaste > region size, - // then retire the region so that subsequent searches can find available memory more quickly. - size_t idx = r->index(); size_t waste_bytes = _partitions.retire_from_partition(orig_partition, idx, r->used()); DEBUG_ONLY(boundary_changed = true;) @@ -1796,7 +1811,6 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo // found the match break; } - end++; } @@ -2036,7 +2050,8 @@ void ShenandoahFreeSet::clear_internal() { _partitions.set_bias_from_left_to_right(ShenandoahFreeSetPartitionId::OldCollector, false); } -void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_regions, size_t &old_trashed_regions, +// Returns total allocatable words in Mutator partition +size_t ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_regions, size_t &old_trashed_regions, size_t &first_old_region, size_t &last_old_region, size_t &old_region_count) { // This resets all state information, removing all regions from all sets. @@ -2054,6 +2069,8 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r size_t region_size_bytes = _partitions.region_size_bytes(); size_t max_regions = _partitions.max(); + size_t mutator_alloc_capacity_in_words = 0; + size_t mutator_leftmost = max_regions; size_t mutator_rightmost = 0; size_t mutator_leftmost_empty = max_regions; @@ -2123,6 +2140,7 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r if (region->is_trash() || !region->is_old()) { // Both young and old (possibly immediately) collected regions (trashed) are placed into the Mutator set _partitions.raw_assign_membership(idx, ShenandoahFreeSetPartitionId::Mutator); + mutator_alloc_capacity_in_words += ac / HeapWordSize; if (idx < mutator_leftmost) { mutator_leftmost = idx; } @@ -2279,6 +2297,7 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r _partitions.rightmost(ShenandoahFreeSetPartitionId::Mutator), _partitions.leftmost(ShenandoahFreeSetPartitionId::OldCollector), _partitions.rightmost(ShenandoahFreeSetPartitionId::OldCollector)); + return mutator_alloc_capacity_in_words; } void ShenandoahFreeSet::transfer_humongous_regions_from_mutator_to_old_collector(size_t xfer_regions, @@ -2583,19 +2602,20 @@ void ShenandoahFreeSet::prepare_to_rebuild(size_t &young_trashed_regions, size_t clear(); log_debug(gc, free)("Rebuilding FreeSet"); - // This places regions that have alloc_capacity into the old_collector set if they identify as is_old() or the - // mutator set otherwise. All trashed (cset) regions are affiliated young and placed in mutator set. - find_regions_with_alloc_capacity(young_trashed_regions, old_trashed_regions, - first_old_region, last_old_region, old_region_count); + // Place regions that have alloc_capacity into the old_collector set if they identify as is_old() or the + // mutator set otherwise. All trashed (cset) regions are affiliated young and placed in mutator set. Save the + // allocatable words in mutator partition in state variable. + _prepare_to_rebuild_mutator_free = find_regions_with_alloc_capacity(young_trashed_regions, old_trashed_regions, + first_old_region, last_old_region, old_region_count); } - -void ShenandoahFreeSet::finish_rebuild(size_t young_cset_regions, size_t old_cset_regions, size_t old_region_count) { +// Return mutator free +void ShenandoahFreeSet::finish_rebuild(size_t young_trashed_regions, size_t old_trashed_regions, size_t old_region_count) { shenandoah_assert_heaplocked(); size_t young_reserve(0), old_reserve(0); if (_heap->mode()->is_generational()) { - compute_young_and_old_reserves(young_cset_regions, old_cset_regions, young_reserve, old_reserve); + compute_young_and_old_reserves(young_trashed_regions, old_trashed_regions, young_reserve, old_reserve); } else { young_reserve = (_heap->max_capacity() / 100) * ShenandoahEvacReserve; old_reserve = 0; @@ -2744,10 +2764,13 @@ void ShenandoahFreeSet::compute_young_and_old_reserves(size_t young_trashed_regi // into the collector set or old collector set in order to assure that the memory available for allocations within // the collector set is at least to_reserve and the memory available for allocations within the old collector set // is at least to_reserve_old. -void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old, size_t &old_region_count, - size_t &young_used_regions, size_t &old_used_regions, - size_t &young_used_bytes, size_t &old_used_bytes) { +// +// Returns total mutator alloc capacity, in words. +size_t ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old, size_t &old_region_count, + size_t &young_used_regions, size_t &old_used_regions, + size_t &young_used_bytes, size_t &old_used_bytes) { const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); + size_t mutator_allocatable_words = _prepare_to_rebuild_mutator_free; young_used_regions = 0; old_used_regions = 0; @@ -2825,6 +2848,8 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old _partitions.leftmost(ShenandoahFreeSetPartitionId::OldCollector), _partitions.rightmost(ShenandoahFreeSetPartitionId::OldCollector)); old_region_count++; + assert(ac = ShenandoahHeapRegion::region_size_bytes(), "Cannot move to old unless entire region is in alloc capacity"); + mutator_allocatable_words -= ShenandoahHeapRegion::region_size_words(); continue; } } @@ -2868,8 +2893,10 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old " Collector range [%zd, %zd]", _partitions.leftmost(ShenandoahFreeSetPartitionId::Mutator), _partitions.rightmost(ShenandoahFreeSetPartitionId::Mutator), - _partitions.leftmost(ShenandoahFreeSetPartitionId::Collector), - _partitions.rightmost(ShenandoahFreeSetPartitionId::Collector)); + _partitions.leftmost(ShenandoahFreeSetPartitionId::OldCollector), + _partitions.rightmost(ShenandoahFreeSetPartitionId::OldCollector)); + + mutator_allocatable_words -= ac / HeapWordSize; continue; } @@ -2977,6 +3004,7 @@ void ShenandoahFreeSet::reserve_regions(size_t to_reserve, size_t to_reserve_old PROPERFMTARGS(to_reserve), PROPERFMTARGS(reserve)); } } + return mutator_allocatable_words; } void ShenandoahFreeSet::establish_old_collector_alloc_bias() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index d55a06d5713..2df06432bd2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -437,6 +437,12 @@ private: ShenandoahHeap* const _heap; ShenandoahRegionPartitions _partitions; + size_t _total_bytes_previously_allocated; + size_t _mutator_bytes_at_last_sample; + + // Temporarily holds mutator_Free allocatable bytes between prepare_to_rebuild() and finish_rebuild() + size_t _prepare_to_rebuild_mutator_free; + // This locks the rebuild process (in combination with the global heap lock). Whenever we rebuild the free set, // we first acquire the global heap lock and then we acquire this _rebuild_lock in a nested context. Threads that // need to check available, acquire only the _rebuild_lock to make sure that they are not obtaining the value of @@ -446,10 +452,10 @@ private: // locks will acquire them in the same order: first the global heap lock and then the rebuild lock. ShenandoahRebuildLock _rebuild_lock; - size_t _total_humongous_waste; - HeapWord* allocate_aligned_plab(size_t size, ShenandoahAllocRequest& req, ShenandoahHeapRegion* r); + size_t _total_humongous_waste; + // We re-evaluate the left-to-right allocation bias whenever _alloc_bias_weight is less than zero. Each time // we allocate an object, we decrement the count of this value. Each time we re-evaluate whether to allocate // from right-to-left or left-to-right, we reset the value of this counter to _InitialAllocBiasWeight. @@ -662,10 +668,47 @@ public: void increase_bytes_allocated(size_t bytes); + // Return an approximation of the bytes allocated since GC start. The value returned is monotonically non-decreasing + // in time within each GC cycle. For certain GC cycles, the value returned may include some bytes allocated before + // the start of the current GC cycle. inline size_t get_bytes_allocated_since_gc_start() const { return _mutator_bytes_allocated_since_gc_start; } + inline size_t get_total_bytes_allocated() { + return _mutator_bytes_allocated_since_gc_start + _total_bytes_previously_allocated; + } + + inline size_t get_bytes_allocated_since_previous_sample() { + size_t total_bytes = get_total_bytes_allocated(); + size_t result; + if (total_bytes < _mutator_bytes_at_last_sample) { + // This rare condition may occur if bytes allocated overflows (wraps around) size_t tally of allocations. + // This may also occur in the very rare situation that get_total_bytes_allocated() is queried in the middle of + // reset_bytes_allocated_since_gc_start(). Note that there is no lock to assure that the two global variables + // it modifies are modified atomically (_total_bytes_previously_allocated and _mutator_byts_allocated_since_gc_start) + // This has been observed to occur when an out-of-cycle degenerated cycle is starting (and thus calls + // reset_bytes_allocated_since_gc_start()) at the same time that the control (non-generational mode) or + // regulator (generational-mode) thread calls should_start_gc() (which invokes get_bytes_allocated_since_previous_sample()). + // + // Handle this rare situation by responding with the "innocent" value 0 and resetting internal state so that the + // the next query can recalibrate. + result = 0; + } else { + // Note: there's always the possibility that the tally of total allocations exceeds the 64-bit capacity of our size_t + // counter. We assume that the difference between relevant samples does not exceed this count. Example: + // Suppose _mutator_words_at_last_sample is 0xffff_ffff_ffff_fff0 (18,446,744,073,709,551,600 Decimal) + // and _total_words is 0x0000_0000_0000_0800 ( 32,768 Decimal) + // Then, total_words - _mutator_words_at_last_sample can be done adding 1's complement of subtrahend: + // 1's complement of _mutator_words_at_last_sample is: 0x0000_0000_0000_0010 ( 16 Decimal)) + // plus total_words: 0x0000_0000_0000_0800 (32,768 Decimal) + // sum: 0x0000_0000_0000_0810 (32,784 Decimal) + result = total_bytes - _mutator_bytes_at_last_sample; + } + _mutator_bytes_at_last_sample = total_bytes; + return result; + } + // Public because ShenandoahRegionPartitions assertions require access. inline size_t alloc_capacity(ShenandoahHeapRegion *r) const; inline size_t alloc_capacity(size_t idx) const; @@ -781,15 +824,15 @@ public: // Acquire heap lock and log status, assuming heap lock is not acquired by the caller. void log_status_under_lock(); - // Note that capacity is the number of regions that had available memory at most recent rebuild. It is not the - // entire size of the young or global generation. (Regions within the generation that were fully utilized at time of - // rebuild are not counted as part of capacity.) - - // All three of the following functions may produce stale data if called without owning the global heap lock. + // All four of the following functions may produce stale data if called without owning the global heap lock. // Changes to the values of these variables are performed with a lock. A change to capacity or used "atomically" // adjusts available with respect to lock holders. However, sequential calls to these three functions may produce // inconsistent data: available may not equal capacity - used because the intermediate states of any "atomic" // locked action can be seen by these unlocked functions. + + // Note that capacity is the number of regions that had available memory at most recent rebuild. It is not the + // entire size of the young or global generation. (Regions within the generation that were fully utilized at time of + // rebuild are not counted as part of capacity.) inline size_t capacity_holding_lock() const { shenandoah_assert_heaplocked(); return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Mutator); @@ -808,11 +851,14 @@ public: ShenandoahRebuildLocker locker(rebuild_lock()); return _partitions.used_by(ShenandoahFreeSetPartitionId::Mutator); } + inline size_t reserved() const { return _partitions.capacity_of(ShenandoahFreeSetPartitionId::Collector); } inline size_t available() { shenandoah_assert_not_heaplocked(); ShenandoahRebuildLocker locker(rebuild_lock()); return _partitions.available_in_locked_for_rebuild(ShenandoahFreeSetPartitionId::Mutator); } + inline size_t available_holding_lock() const + { return _partitions.available_in(ShenandoahFreeSetPartitionId::Mutator); } // Use this version of available() if the heap lock is held. inline size_t available_locked() const { @@ -880,13 +926,17 @@ public: // first_old_region is the index of the first region that is part of the OldCollector set // last_old_region is the index of the last region that is part of the OldCollector set // old_region_count is the number of regions in the OldCollector set that have memory available to be allocated - void find_regions_with_alloc_capacity(size_t &young_cset_regions, size_t &old_cset_regions, - size_t &first_old_region, size_t &last_old_region, size_t &old_region_count); + // + // Returns allocatable memory within Mutator partition, in words. + size_t find_regions_with_alloc_capacity(size_t &young_cset_regions, size_t &old_cset_regions, + size_t &first_old_region, size_t &last_old_region, size_t &old_region_count); // Ensure that Collector has at least to_reserve bytes of available memory, and OldCollector has at least old_reserve // bytes of available memory. On input, old_region_count holds the number of regions already present in the // OldCollector partition. Upon return, old_region_count holds the updated number of regions in the OldCollector partition. - void reserve_regions(size_t to_reserve, size_t old_reserve, size_t &old_region_count, + // + // Returns allocatable memory within Mutator partition, in words. + size_t reserve_regions(size_t to_reserve, size_t old_reserve, size_t &old_region_count, size_t &young_used_regions, size_t &old_used_regions, size_t &young_used_bytes, size_t &old_used_bytes); // Reserve space for evacuations, with regions reserved for old evacuations placed to the right diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 3c92750cc0c..750f7e9122d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -252,6 +252,7 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { phase5_epilog(); } + heap->start_idle_span(); // Resize metaspace MetaspaceGC::compute_new_size(); @@ -1124,8 +1125,9 @@ void ShenandoahFullGC::phase5_epilog() { if (heap->mode()->is_generational()) { ShenandoahGenerationalFullGC::compute_balances(); } - free_set->finish_rebuild(young_trashed_regions, old_trashed_regions, num_old); + heap->free_set()->finish_rebuild(young_trashed_regions, old_trashed_regions, num_old); } + // Set mark incomplete because the marking bitmaps have been reset except pinned regions. _generation->set_mark_incomplete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index ddb50ee0020..b2d5e5423dd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -151,6 +151,10 @@ ShenandoahHeuristics* ShenandoahGeneration::initialize_heuristics(ShenandoahMode return _heuristics; } +void ShenandoahGeneration::post_initialize_heuristics() { + _heuristics->post_initialize(); +} + void ShenandoahGeneration::set_evacuation_reserve(size_t new_val) { shenandoah_assert_heaplocked(); _evacuation_reserve = new_val; @@ -358,8 +362,7 @@ void ShenandoahGeneration::cancel_marking() { set_concurrent_mark_in_progress(false); } -ShenandoahGeneration::ShenandoahGeneration(ShenandoahGenerationType type, - uint max_workers) : +ShenandoahGeneration::ShenandoahGeneration(ShenandoahGenerationType type, uint max_workers) : _type(type), _task_queues(new ShenandoahObjToScanQueueSet(max_workers)), _ref_processor(new ShenandoahReferenceProcessor(this, MAX2(max_workers, 1U))), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 946f2b91520..1a549be8988 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -83,10 +83,10 @@ private: ShenandoahReferenceProcessor* ref_processor() { return _ref_processor; } virtual ShenandoahHeuristics* initialize_heuristics(ShenandoahMode* gc_mode); + virtual void post_initialize_heuristics(); virtual void post_initialize(ShenandoahHeap* heap); - virtual size_t bytes_allocated_since_gc_start() const override = 0; virtual size_t used() const override = 0; virtual size_t used_regions() const = 0; virtual size_t used_regions_size() const = 0; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 3b57190cc75..cc7547b8ac1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -622,10 +622,11 @@ void ShenandoahGenerationalControlThread::service_stw_full_cycle(GCCause::Cause void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const ShenandoahGCRequest& request) { assert(_degen_point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set"); + request.generation->heuristics()->record_degenerated_cycle_start(ShenandoahGC::ShenandoahDegenPoint::_degenerated_outside_cycle + == _degen_point); _heap->increment_total_collections(false); ShenandoahGCSession session(request.cause, request.generation); - ShenandoahDegenGC gc(_degen_point, request.generation); gc.collect(request.cause); _degen_point = ShenandoahGC::_degenerated_unset; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 2c2e5533c01..b302bde8510 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -90,11 +90,23 @@ ShenandoahGenerationalHeap::ShenandoahGenerationalHeap(ShenandoahCollectorPolicy assert(is_aligned(_max_plab_size, CardTable::card_size_in_words()), "max_plab_size must be aligned"); } +void ShenandoahGenerationalHeap::initialize_generations() { + ShenandoahHeap::initialize_generations(); + _young_generation->post_initialize(this); + _old_generation->post_initialize(this); +} + void ShenandoahGenerationalHeap::post_initialize() { ShenandoahHeap::post_initialize(); _age_census = new ShenandoahAgeCensus(); } +void ShenandoahGenerationalHeap::post_initialize_heuristics() { + ShenandoahHeap::post_initialize_heuristics(); + _young_generation->post_initialize_heuristics(); + _old_generation->post_initialize_heuristics(); +} + void ShenandoahGenerationalHeap::print_init_logger() const { ShenandoahGenerationalInitLogger logger; logger.print_all(); @@ -110,12 +122,6 @@ void ShenandoahGenerationalHeap::initialize_heuristics() { _old_generation->initialize_heuristics(mode()); } -void ShenandoahGenerationalHeap::post_initialize_heuristics() { - ShenandoahHeap::post_initialize_heuristics(); - _young_generation->post_initialize(this); - _old_generation->post_initialize(this); -} - void ShenandoahGenerationalHeap::initialize_serviceability() { assert(mode()->is_generational(), "Only for the generational mode"); _young_gen_memory_pool = new ShenandoahYoungGenMemoryPool(this); @@ -152,6 +158,10 @@ void ShenandoahGenerationalHeap::stop() { regulator_thread()->stop(); } +void ShenandoahGenerationalHeap::start_idle_span() { + young_generation()->heuristics()->start_idle_span(); +} + bool ShenandoahGenerationalHeap::requires_barriers(stackChunkOop obj) const { if (is_idle()) { return false; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index 719bae52a83..7fe0362aa3f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -40,6 +40,7 @@ class ShenandoahGenerationalHeap : public ShenandoahHeap { public: explicit ShenandoahGenerationalHeap(ShenandoahCollectorPolicy* policy); void post_initialize() override; + void initialize_generations() override; void initialize_heuristics() override; void post_initialize_heuristics() override; @@ -82,6 +83,8 @@ public: inline bool is_tenurable(const ShenandoahHeapRegion* r) const; + void start_idle_span() override; + // Ages regions that haven't been used for allocations in the current cycle. // Resets ages for regions that have been used for allocations. void update_region_ages(ShenandoahMarkingContext* ctx); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index d78bdae6a51..c6889351161 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -435,7 +435,7 @@ jint ShenandoahHeap::initialize() { } _free_set = new ShenandoahFreeSet(this, _num_regions); - post_initialize_heuristics(); + initialize_generations(); // We are initializing free set. We ignore cset region tallies. size_t young_trashed_regions, old_trashed_regions, first_old, last_old, num_old; @@ -492,16 +492,17 @@ jint ShenandoahHeap::initialize() { _phase_timings = new ShenandoahPhaseTimings(max_workers()); ShenandoahCodeRoots::initialize(); + // Initialization of controller makes use of variables established by initialize_heuristics. initialize_controller(); + // Certain initialization of heuristics must be deferred until after controller is initialized. + post_initialize_heuristics(); + start_idle_span(); if (ShenandoahUncommit) { _uncommit_thread = new ShenandoahUncommitThread(this); } - print_init_logger(); - FullGCForwarding::initialize(_heap_region); - return JNI_OK; } @@ -545,10 +546,6 @@ void ShenandoahHeap::initialize_heuristics() { _global_generation->initialize_heuristics(mode()); } -void ShenandoahHeap::post_initialize_heuristics() { - _global_generation->post_initialize(this); -} - #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable:4355 ) // 'this' : used in base member initializer list @@ -690,6 +687,11 @@ public: } }; +void ShenandoahHeap::initialize_generations() { + _global_generation->post_initialize(this); +} + +// We do not call this explicitly It is called by Hotspot infrastructure. void ShenandoahHeap::post_initialize() { CollectedHeap::post_initialize(); @@ -717,6 +719,10 @@ void ShenandoahHeap::post_initialize() { JFR_ONLY(ShenandoahJFRSupport::register_jfr_type_serializers();) } +void ShenandoahHeap::post_initialize_heuristics() { + _global_generation->post_initialize_heuristics(); +} + ShenandoahHeuristics* ShenandoahHeap::heuristics() { return _global_generation->heuristics(); } @@ -760,6 +766,7 @@ void ShenandoahHeap::set_soft_max_capacity(size_t v) { "Should be in bounds: %zu <= %zu <= %zu", min_capacity(), v, max_capacity()); _soft_max_size.store_relaxed(v); + heuristics()->compute_headroom_adjustment(); } size_t ShenandoahHeap::min_capacity() const { @@ -835,6 +842,10 @@ void ShenandoahHeap::notify_heap_changed() { _heap_changed.try_set(); } +void ShenandoahHeap::start_idle_span() { + heuristics()->start_idle_span(); +} + void ShenandoahHeap::set_forced_counters_update(bool value) { monitoring_support()->set_forced_counters_update(value); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 85ad339469d..d4604be0aec 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -195,6 +195,7 @@ public: ShenandoahHeap(ShenandoahCollectorPolicy* policy); jint initialize() override; void post_initialize() override; + virtual void initialize_generations(); void initialize_mode(); virtual void initialize_heuristics(); virtual void post_initialize_heuristics(); @@ -393,6 +394,8 @@ public: return _heap_changed.try_unset(); } + virtual void start_idle_span(); + void set_concurrent_young_mark_in_progress(bool in_progress); void set_concurrent_old_mark_in_progress(bool in_progress); void set_evacuation_in_progress(bool in_progress); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 4fda65b4030..1b12909bcaf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -422,6 +422,7 @@ void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent // At the end of old-gen, we may find that we have reclaimed immediate garbage, allowing a longer allocation runway. // We may also find that we have accumulated canddiate regions for mixed evacuation. If so, we will want to expand // the OldCollector reserve in order to make room for these mixed evacuations. + assert(ShenandoahHeap::heap()->mode()->is_generational(), "sanity"); assert(young_trash_regions == 0, "sanity"); ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); @@ -765,6 +766,7 @@ size_t ShenandoahOldGeneration::used_regions_size() const { return used_regions * ShenandoahHeapRegion::region_size_bytes(); } +// For the old generation, max_capacity() equals soft_max_capacity() size_t ShenandoahOldGeneration::max_capacity() const { size_t total_regions = _free_set->total_old_regions(); return total_regions * ShenandoahHeapRegion::region_size_bytes(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp index ec4b7c7217c..fe92a3a3e08 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp @@ -36,7 +36,8 @@ ShenandoahRegulatorThread::ShenandoahRegulatorThread(ShenandoahGenerationalContr _heap(ShenandoahHeap::heap()), _control_thread(control_thread), _sleep(ShenandoahControlIntervalMin), - _last_sleep_adjust_time(os::elapsedTime()) { + _most_recent_wake_time(os::elapsedTime()), + _last_sleep_adjust_time(_most_recent_wake_time) { shenandoah_assert_generational(); _old_heuristics = _heap->old_generation()->heuristics(); _young_heuristics = _heap->young_generation()->heuristics(); @@ -115,19 +116,22 @@ void ShenandoahRegulatorThread::regulator_sleep() { // Wait before performing the next action. If allocation happened during this wait, // we exit sooner, to let heuristics re-evaluate new conditions. If we are at idle, // back off exponentially. - double current = os::elapsedTime(); - + double before_sleep_time = _most_recent_wake_time; if (ShenandoahHeap::heap()->has_changed()) { _sleep = ShenandoahControlIntervalMin; - } else if ((current - _last_sleep_adjust_time) * 1000 > ShenandoahControlIntervalAdjustPeriod){ + } else if ((before_sleep_time - _last_sleep_adjust_time) * 1000 > ShenandoahControlIntervalAdjustPeriod){ _sleep = MIN2(ShenandoahControlIntervalMax, MAX2(1u, _sleep * 2)); - _last_sleep_adjust_time = current; + _last_sleep_adjust_time = before_sleep_time; } SuspendibleThreadSetLeaver leaver; os::naked_short_sleep(_sleep); + double wake_time = os::elapsedTime(); + _most_recent_period = wake_time - _most_recent_wake_time; + _most_recent_wake_time = wake_time; + _young_heuristics->update_should_start_query_times(_most_recent_wake_time, double(_sleep) / 1000.0); if (LogTarget(Debug, gc, thread)::is_enabled()) { - double elapsed = os::elapsedTime() - current; + double elapsed = _most_recent_wake_time - before_sleep_time; double hiccup = elapsed - double(_sleep); if (hiccup > 0.001) { log_debug(gc, thread)("Regulator hiccup time: %.3fs", hiccup); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp index 2519025b6fb..cc41bc2c65b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp @@ -79,7 +79,10 @@ class ShenandoahRegulatorThread: public ConcurrentGCThread { ShenandoahOldHeuristics* _old_heuristics; ShenandoahHeuristics* _global_heuristics; + // duration of planned regulator sleep period, in ms uint _sleep; + double _most_recent_wake_time; + double _most_recent_period; double _last_sleep_adjust_time; }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 3eb1a06a911..d3e9a1f9fae 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -34,6 +34,59 @@ range, \ constraint) \ \ + product(uint, ShenandoahAccelerationSamplePeriod, 15, EXPERIMENTAL, \ + "When at least this much time (measured in ms) has passed " \ + "since the acceleration allocation rate was most recently " \ + "sampled, capture another allocation rate sample for the purpose "\ + "of detecting acceleration or momentary spikes in allocation " \ + "rate. A smaller value allows quicker response to changes in " \ + "allocation rates but is more vulnerable to noise and requires " \ + "more monitoring effort.") \ + range(1, 1000) \ + \ + product(uint, ShenandoahRateAccelerationSampleSize, 8, EXPERIMENTAL, \ + "In selected ShenandoahControlIntervals " \ + "(if ShenandoahAccelerationSamplePeriod ms have passed " \ + "since previous allocation rate sample), " \ + "we compute the allocation rate since the previous rate was " \ + "sampled. This many samples are analyzed to determine whether " \ + "allocation rates are accelerating. Acceleration may occur " \ + "due to increasing client demand or due to phase changes in " \ + "an application. A larger value reduces sensitivity to " \ + "noise and delays recognition of the accelerating trend. A " \ + "larger value may also cause the heuristic to miss detection " \ + "of very quick accelerations. Smaller values may cause random " \ + "noise to be perceived as acceleration of allocation rate, " \ + "triggering excess collections. Note that the acceleration " \ + "need not last the entire span of the sampled duration to be " \ + "detected. If the last several of all samples are signficantly " \ + "larger than the other samples, the best fit line through all " \ + "sampled values will have an upward slope, manifesting as " \ + "acceleration.") \ + range(1,64) \ + \ + product(uint, ShenandoahMomentaryAllocationRateSpikeSampleSize, \ + 2, EXPERIMENTAL, \ + "In selected ShenandoahControlIntervals " \ + "(if ShenandoahAccelerationSamplePeriod ms have passed " \ + "since previous allocation rate sample), we compute " \ + "the allocation rate since the previous rate was sampled. " \ + "The weighted average of this " \ + "many most recent momentary allocation rate samples is compared " \ + "against current allocation runway and anticipated GC time to " \ + "determine whether a spike in momentary allocation rate " \ + "justifies an early GC trigger. Momentary allocation spike " \ + "detection is in addition to previously implemented " \ + "ShenandoahAdaptiveInitialSpikeThreshold, the latter of which " \ + "is more effective at detecting slower spikes. The latter " \ + "spike detection samples at the rate specifieid by " \ + "ShenandoahAdaptiveSampleFrequencyHz. The value of this " \ + "parameter must be less than the value of " \ + "ShenandoahRateAccelerationSampleSize. A larger value makes " \ + "momentary spike detection less sensitive. A smaller value " \ + "may result in excessive GC triggers.") \ + range(1,64) \ + \ product(uintx, ShenandoahGenerationalMinPIPUsage, 30, EXPERIMENTAL, \ "(Generational mode only) What percent of a heap region " \ "should be used before we consider promoting a region in " \ From 297812eec1ad5c9f48822ace2bd720fd02c6b263 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 3 Mar 2026 09:54:54 +0000 Subject: [PATCH 005/655] 8378867: jpackage references non-existing "message.app-image-requires-identifier" l10n key Reviewed-by: almatvee --- .../internal/MacApplicationBuilder.java | 9 +++--- .../resources/MacResources.properties | 2 ++ .../cli/OptionsValidationFailTest.excludes | 1 + test/jdk/tools/jpackage/share/ErrorTest.java | 31 ++++++++++++++++++- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index a73a6152f6d..43590fb5e2c 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -32,7 +32,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import jdk.jpackage.internal.util.RootedPath; import java.util.stream.Stream; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.AppImageSigningConfig; @@ -40,6 +39,8 @@ import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.MacApplicationMixin; +import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.util.RootedPath; final class MacApplicationBuilder { @@ -183,10 +184,8 @@ final class MacApplicationBuilder { } catch (IOException ex) { throw new UncheckedIOException(ex); } catch (Exception ex) { - throw I18N.buildConfigException("message.app-image-requires-identifier") - .advice("message.app-image-requires-identifier.advice") - .cause(ex) - .create(); + throw new JPackageException( + I18N.format("error.invalid-app-image-plist-file", externalInfoPlistFile), ex); } } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index e43cadc5782..3aebdc39d41 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -31,6 +31,8 @@ error.app-image.mac-sign.required=--mac-sign option is required with predefined error.invalid-runtime-image-missing-file=Runtime image "{0}" is missing "{1}" file error.invalid-runtime-image-bin-dir=Runtime image "{0}" should not contain "bin" folder error.invalid-runtime-image-bin-dir.advice=Use --strip-native-commands jlink option when generating runtime image used with {0} option +error.invalid-app-image-plist-file=Invalid "{0}" file in the predefined application image + resource.app-info-plist=Application Info.plist resource.app-runtime-info-plist=Embedded Java Runtime Info.plist resource.runtime-info-plist=Java Runtime Info.plist diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes index 0b98c051238..f86fb9a3897 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes @@ -23,6 +23,7 @@ ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--mac-app-store, --runtime-imag ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--runtime-image, @@EMPTY_DIR@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@EMPTY_DIR@@, lib/**/libjli.dylib]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--runtime-image, @@INVALID_MAC_RUNTIME_BUNDLE@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@INVALID_MAC_RUNTIME_BUNDLE@@, Contents/Home/lib/**/libjli.dylib]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--runtime-image, @@INVALID_MAC_RUNTIME_IMAGE@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@INVALID_MAC_RUNTIME_IMAGE@@, lib/**/libjli.dylib]]) +ErrorTest.test(NATIVE; args-add=[--app-image, @@MAC_APP_IMAGE_INVALID_INFO_PLIST@@]; errors=[message.error-header+[error.invalid-app-image-plist-file, @@MAC_APP_IMAGE_INVALID_INFO_PLIST@@]]) ErrorTest.test(NATIVE; args-add=[--runtime-image, @@EMPTY_DIR@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@EMPTY_DIR@@, lib/**/libjli.dylib]]) ErrorTest.test(NATIVE; args-add=[--runtime-image, @@INVALID_MAC_RUNTIME_BUNDLE@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@INVALID_MAC_RUNTIME_BUNDLE@@, Contents/Home/lib/**/libjli.dylib]]) ErrorTest.test(NATIVE; args-add=[--runtime-image, @@INVALID_MAC_RUNTIME_IMAGE@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@INVALID_MAC_RUNTIME_IMAGE@@, lib/**/libjli.dylib]]) diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index 2133823381c..8bc7ba2521f 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -26,6 +26,11 @@ import static java.util.stream.Collectors.toMap; import static jdk.internal.util.OperatingSystem.LINUX; import static jdk.internal.util.OperatingSystem.MACOS; import static jdk.internal.util.OperatingSystem.WINDOWS; +import static jdk.jpackage.internal.util.PListWriter.writeDict; +import static jdk.jpackage.internal.util.PListWriter.writePList; +import static jdk.jpackage.internal.util.XmlUtils.createXml; +import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import static jdk.jpackage.test.JPackageCommand.makeAdvice; import static jdk.jpackage.test.JPackageCommand.makeError; @@ -46,6 +51,7 @@ import java.util.regex.Pattern; import java.util.stream.IntStream; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.TokenReplace; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; @@ -54,6 +60,7 @@ import jdk.jpackage.test.CannedArgument; import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageOutputValidator; +import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.MacSign; import jdk.jpackage.test.MacSign.CertificateRequest; import jdk.jpackage.test.MacSign.CertificateType; @@ -105,6 +112,11 @@ public final class ErrorTest { final var appImageRoot = TKit.createTempDirectory("appimage"); final var appImageCmd = JPackageCommand.helloAppImage() + // Use the default jpackage tool provider to create an application image. + // The ErrorTest is used from the OptionsValidationFailTest unit tests that override + // the default jpackage tool provider with the implementation that doesn't do packaging + // and can not create a valid application image. + .useToolProvider(JavaTool.JPACKAGE.asToolProvider()) .setFakeRuntime().setArgumentValue("--dest", appImageRoot); appImageCmd.execute(); @@ -124,6 +136,19 @@ public final class ErrorTest { return appImageCmd.outputBundle(); }), + MAC_APP_IMAGE_INVALID_INFO_PLIST(toFunction(cmd -> { + var appImageDir = (Path)APP_IMAGE.expand(cmd).orElseThrow(); + // Replace the default Info.plist file with an empty one. + var plistFile = new MacBundle(appImageDir).infoPlistFile(); + TKit.trace(String.format("Create invalid plist file in [%s]", plistFile)); + createXml(plistFile, xml -> { + writePList(xml, toXmlConsumer(() -> { + writeDict(xml, toXmlConsumer(() -> { + })); + })); + }); + return appImageDir; + })), INVALID_MAC_RUNTIME_BUNDLE(toSupplier(() -> { // Has "Contents/MacOS/libjli.dylib", but missing "Contents/Home/lib/libjli.dylib". final Path root = TKit.createTempDirectory("mac-invalid-runtime-bundle"); @@ -963,7 +988,11 @@ public final class ErrorTest { testSpec().noAppDesc().nativeType().addArgs("--app-image", Token.EMPTY_DIR.token()) .error("error.parameter-not-mac-bundle", JPackageCommand.cannedArgument(cmd -> { return Path.of(cmd.getArgumentValue("--app-image")); - }, Token.EMPTY_DIR.token()), "--app-image") + }, Token.EMPTY_DIR.token()), "--app-image"), + testSpec().nativeType().noAppDesc().addArgs("--app-image", Token.MAC_APP_IMAGE_INVALID_INFO_PLIST.token()) + .error("error.invalid-app-image-plist-file", JPackageCommand.cannedArgument(cmd -> { + return new MacBundle(Path.of(cmd.getArgumentValue("--app-image"))).infoPlistFile(); + }, Token.MAC_APP_IMAGE_INVALID_INFO_PLIST.token())) ).map(TestSpec.Builder::create).toList()); macInvalidRuntime(testCases::add); From 57db48cc21d47475caf2d1fae6bf37eab8d7521e Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 3 Mar 2026 10:01:00 +0000 Subject: [PATCH 006/655] 8373290: Update FreeType to 2.14.1 Reviewed-by: azvegint, serb, prr --- src/java.desktop/share/legal/freetype.md | 40 +- .../include/freetype/config/ftconfig.h | 2 +- .../include/freetype/config/ftheader.h | 2 +- .../include/freetype/config/ftoption.h | 49 +- .../include/freetype/config/ftstdlib.h | 2 +- .../include/freetype/config/integer-types.h | 31 +- .../include/freetype/config/mac-support.h | 2 +- .../include/freetype/config/public-macros.h | 6 +- .../libfreetype/include/freetype/freetype.h | 98 +- .../libfreetype/include/freetype/ftadvanc.h | 2 +- .../libfreetype/include/freetype/ftbbox.h | 2 +- .../libfreetype/include/freetype/ftbdf.h | 2 +- .../libfreetype/include/freetype/ftbitmap.h | 2 +- .../libfreetype/include/freetype/ftcid.h | 2 +- .../libfreetype/include/freetype/ftcolor.h | 17 +- .../libfreetype/include/freetype/ftdriver.h | 6 +- .../libfreetype/include/freetype/fterrdef.h | 2 +- .../libfreetype/include/freetype/fterrors.h | 2 +- .../libfreetype/include/freetype/ftfntfmt.h | 2 +- .../libfreetype/include/freetype/ftgasp.h | 2 +- .../libfreetype/include/freetype/ftglyph.h | 2 +- .../libfreetype/include/freetype/ftgzip.h | 2 +- .../libfreetype/include/freetype/ftimage.h | 8 +- .../libfreetype/include/freetype/ftincrem.h | 2 +- .../libfreetype/include/freetype/ftlcdfil.h | 2 +- .../libfreetype/include/freetype/ftlist.h | 2 +- .../libfreetype/include/freetype/ftlogging.h | 2 +- .../libfreetype/include/freetype/ftmac.h | 2 +- .../libfreetype/include/freetype/ftmm.h | 256 ++- .../libfreetype/include/freetype/ftmodapi.h | 2 +- .../libfreetype/include/freetype/ftmoderr.h | 2 +- .../libfreetype/include/freetype/ftoutln.h | 2 +- .../libfreetype/include/freetype/ftparams.h | 2 +- .../libfreetype/include/freetype/ftrender.h | 2 +- .../libfreetype/include/freetype/ftsizes.h | 2 +- .../libfreetype/include/freetype/ftsnames.h | 2 +- .../libfreetype/include/freetype/ftstroke.h | 2 +- .../libfreetype/include/freetype/ftsynth.h | 2 +- .../libfreetype/include/freetype/ftsystem.h | 2 +- .../libfreetype/include/freetype/fttrigon.h | 2 +- .../libfreetype/include/freetype/fttypes.h | 2 +- .../include/freetype/internal/autohint.h | 2 +- .../include/freetype/internal/cffotypes.h | 2 +- .../include/freetype/internal/cfftypes.h | 2 +- .../freetype/internal/compiler-macros.h | 6 +- .../include/freetype/internal/ftcalc.h | 300 +-- .../include/freetype/internal/ftdebug.h | 2 +- .../include/freetype/internal/ftdrv.h | 2 +- .../include/freetype/internal/ftgloadr.h | 2 +- .../include/freetype/internal/fthash.h | 23 + .../include/freetype/internal/ftmemory.h | 2 +- .../include/freetype/internal/ftmmtypes.h | 2 +- .../include/freetype/internal/ftobjs.h | 30 +- .../include/freetype/internal/ftpsprop.h | 2 +- .../include/freetype/internal/ftrfork.h | 2 +- .../include/freetype/internal/ftserv.h | 2 +- .../include/freetype/internal/ftstream.h | 2 +- .../include/freetype/internal/fttrace.h | 5 +- .../include/freetype/internal/ftvalid.h | 2 +- .../include/freetype/internal/psaux.h | 2 +- .../include/freetype/internal/pshints.h | 2 +- .../freetype/internal/services/svbdf.h | 2 +- .../freetype/internal/services/svcfftl.h | 2 +- .../freetype/internal/services/svcid.h | 2 +- .../freetype/internal/services/svfntfmt.h | 2 +- .../freetype/internal/services/svgldict.h | 2 +- .../freetype/internal/services/svgxval.h | 2 +- .../freetype/internal/services/svkern.h | 2 +- .../freetype/internal/services/svmetric.h | 4 +- .../include/freetype/internal/services/svmm.h | 2 +- .../freetype/internal/services/svotval.h | 2 +- .../freetype/internal/services/svpfr.h | 2 +- .../freetype/internal/services/svpostnm.h | 2 +- .../freetype/internal/services/svprop.h | 2 +- .../freetype/internal/services/svpscmap.h | 2 +- .../freetype/internal/services/svpsinfo.h | 2 +- .../freetype/internal/services/svsfnt.h | 2 +- .../freetype/internal/services/svttcmap.h | 2 +- .../freetype/internal/services/svtteng.h | 2 +- .../freetype/internal/services/svttglyf.h | 2 +- .../freetype/internal/services/svwinfnt.h | 2 +- .../include/freetype/internal/sfnt.h | 8 +- .../include/freetype/internal/svginterface.h | 2 +- .../include/freetype/internal/t1types.h | 2 +- .../include/freetype/internal/tttypes.h | 41 +- .../include/freetype/internal/wofftypes.h | 2 +- .../libfreetype/include/freetype/otsvg.h | 2 +- .../libfreetype/include/freetype/t1tables.h | 2 +- .../libfreetype/include/freetype/ttnameid.h | 258 +-- .../libfreetype/include/freetype/tttables.h | 13 +- .../libfreetype/include/freetype/tttags.h | 2 +- .../native/libfreetype/include/ft2build.h | 2 +- .../native/libfreetype/src/autofit/afadjust.c | 1612 +++++++++++++++++ .../native/libfreetype/src/autofit/afadjust.h | 130 ++ .../native/libfreetype/src/autofit/afblue.c | 194 +- .../native/libfreetype/src/autofit/afblue.cin | 2 +- .../native/libfreetype/src/autofit/afblue.dat | 194 +- .../native/libfreetype/src/autofit/afblue.h | 11 +- .../native/libfreetype/src/autofit/afblue.hin | 11 +- .../native/libfreetype/src/autofit/afcjk.c | 49 +- .../native/libfreetype/src/autofit/afcjk.h | 2 +- .../native/libfreetype/src/autofit/afcover.h | 2 +- .../native/libfreetype/src/autofit/afdummy.c | 2 +- .../native/libfreetype/src/autofit/afdummy.h | 2 +- .../native/libfreetype/src/autofit/aferrors.h | 2 +- .../native/libfreetype/src/autofit/afglobal.c | 40 +- .../native/libfreetype/src/autofit/afglobal.h | 15 +- .../native/libfreetype/src/autofit/afhints.c | 23 +- .../native/libfreetype/src/autofit/afhints.h | 19 +- .../native/libfreetype/src/autofit/afindic.c | 2 +- .../native/libfreetype/src/autofit/afindic.h | 2 +- .../native/libfreetype/src/autofit/aflatin.c | 1555 +++++++++++++++- .../native/libfreetype/src/autofit/aflatin.h | 25 +- .../native/libfreetype/src/autofit/afloader.c | 2 +- .../native/libfreetype/src/autofit/afloader.h | 2 +- .../native/libfreetype/src/autofit/afmodule.c | 14 +- .../native/libfreetype/src/autofit/afmodule.h | 8 +- .../native/libfreetype/src/autofit/afranges.c | 63 +- .../native/libfreetype/src/autofit/afranges.h | 2 +- .../native/libfreetype/src/autofit/afscript.h | 2 +- .../native/libfreetype/src/autofit/afshaper.c | 340 ++-- .../native/libfreetype/src/autofit/afshaper.h | 19 +- .../native/libfreetype/src/autofit/afstyles.h | 58 +- .../native/libfreetype/src/autofit/aftypes.h | 6 +- .../libfreetype/src/autofit/afws-decl.h | 2 +- .../libfreetype/src/autofit/afws-iter.h | 2 +- .../native/libfreetype/src/autofit/ft-hb.c | 197 ++ .../native/libfreetype/src/autofit/ft-hb.h | 82 + .../native/libfreetype/src/base/ftadvanc.c | 2 +- .../native/libfreetype/src/base/ftbase.h | 4 +- .../native/libfreetype/src/base/ftbbox.c | 2 +- .../native/libfreetype/src/base/ftbitmap.c | 12 +- .../native/libfreetype/src/base/ftcalc.c | 146 +- .../share/native/libfreetype/src/base/ftcid.c | 2 +- .../native/libfreetype/src/base/ftcolor.c | 21 +- .../native/libfreetype/src/base/ftdbgmem.c | 3 +- .../native/libfreetype/src/base/ftdebug.c | 4 +- .../native/libfreetype/src/base/ftfntfmt.c | 2 +- .../native/libfreetype/src/base/ftfstype.c | 2 +- .../native/libfreetype/src/base/ftgasp.c | 2 +- .../native/libfreetype/src/base/ftgloadr.c | 2 +- .../native/libfreetype/src/base/ftglyph.c | 2 +- .../native/libfreetype/src/base/fthash.c | 104 +- .../native/libfreetype/src/base/ftinit.c | 2 +- .../native/libfreetype/src/base/ftlcdfil.c | 2 +- .../share/native/libfreetype/src/base/ftmac.c | 2 +- .../share/native/libfreetype/src/base/ftmm.c | 37 +- .../native/libfreetype/src/base/ftobjs.c | 64 +- .../native/libfreetype/src/base/ftoutln.c | 2 +- .../native/libfreetype/src/base/ftpatent.c | 2 +- .../native/libfreetype/src/base/ftpsprop.c | 2 +- .../native/libfreetype/src/base/ftrfork.c | 10 +- .../native/libfreetype/src/base/ftsnames.c | 2 +- .../native/libfreetype/src/base/ftstream.c | 4 +- .../native/libfreetype/src/base/ftstroke.c | 24 +- .../native/libfreetype/src/base/ftsynth.c | 4 +- .../native/libfreetype/src/base/ftsystem.c | 4 +- .../native/libfreetype/src/base/fttrigon.c | 2 +- .../native/libfreetype/src/base/fttype1.c | 2 +- .../native/libfreetype/src/base/ftutil.c | 2 +- .../native/libfreetype/src/cff/cffcmap.c | 2 +- .../native/libfreetype/src/cff/cffcmap.h | 2 +- .../native/libfreetype/src/cff/cffdrivr.c | 162 +- .../native/libfreetype/src/cff/cffdrivr.h | 2 +- .../native/libfreetype/src/cff/cfferrs.h | 2 +- .../native/libfreetype/src/cff/cffgload.c | 70 +- .../native/libfreetype/src/cff/cffgload.h | 2 +- .../native/libfreetype/src/cff/cffload.c | 16 +- .../native/libfreetype/src/cff/cffload.h | 2 +- .../native/libfreetype/src/cff/cffobjs.c | 16 +- .../native/libfreetype/src/cff/cffobjs.h | 2 +- .../native/libfreetype/src/cff/cffparse.c | 10 +- .../native/libfreetype/src/cff/cffparse.h | 2 +- .../native/libfreetype/src/cff/cfftoken.h | 2 +- .../native/libfreetype/src/cid/ciderrs.h | 2 +- .../native/libfreetype/src/cid/cidgload.c | 46 +- .../native/libfreetype/src/cid/cidgload.h | 2 +- .../native/libfreetype/src/cid/cidload.c | 2 +- .../native/libfreetype/src/cid/cidload.h | 2 +- .../native/libfreetype/src/cid/cidobjs.c | 2 +- .../native/libfreetype/src/cid/cidobjs.h | 2 +- .../native/libfreetype/src/cid/cidparse.c | 2 +- .../native/libfreetype/src/cid/cidparse.h | 2 +- .../native/libfreetype/src/cid/cidriver.c | 2 +- .../native/libfreetype/src/cid/cidriver.h | 2 +- .../native/libfreetype/src/cid/cidtoken.h | 2 +- .../native/libfreetype/src/psaux/afmparse.c | 2 +- .../native/libfreetype/src/psaux/afmparse.h | 2 +- .../native/libfreetype/src/psaux/cffdecode.c | 6 +- .../native/libfreetype/src/psaux/cffdecode.h | 2 +- .../native/libfreetype/src/psaux/psauxerr.h | 2 +- .../native/libfreetype/src/psaux/psauxmod.c | 2 +- .../native/libfreetype/src/psaux/psauxmod.h | 5 +- .../native/libfreetype/src/psaux/psconv.c | 2 +- .../native/libfreetype/src/psaux/psconv.h | 2 +- .../native/libfreetype/src/psaux/psintrp.c | 2 +- .../native/libfreetype/src/psaux/psobjs.c | 9 +- .../native/libfreetype/src/psaux/psobjs.h | 2 +- .../native/libfreetype/src/psaux/t1cmap.c | 2 +- .../native/libfreetype/src/psaux/t1cmap.h | 2 +- .../native/libfreetype/src/psaux/t1decode.c | 4 +- .../native/libfreetype/src/psaux/t1decode.h | 2 +- .../native/libfreetype/src/pshinter/pshalgo.c | 4 +- .../native/libfreetype/src/pshinter/pshalgo.h | 2 +- .../native/libfreetype/src/pshinter/pshglob.c | 2 +- .../native/libfreetype/src/pshinter/pshglob.h | 2 +- .../native/libfreetype/src/pshinter/pshmod.c | 2 +- .../native/libfreetype/src/pshinter/pshmod.h | 2 +- .../libfreetype/src/pshinter/pshnterr.h | 2 +- .../native/libfreetype/src/pshinter/pshrec.c | 12 +- .../native/libfreetype/src/pshinter/pshrec.h | 2 +- .../native/libfreetype/src/psnames/psmodule.c | 2 +- .../native/libfreetype/src/psnames/psmodule.h | 2 +- .../native/libfreetype/src/psnames/psnamerr.h | 2 +- .../native/libfreetype/src/psnames/pstables.h | 2 +- .../native/libfreetype/src/raster/ftmisc.h | 2 +- .../native/libfreetype/src/raster/ftraster.c | 18 +- .../native/libfreetype/src/raster/ftraster.h | 2 +- .../native/libfreetype/src/raster/ftrend1.c | 2 +- .../native/libfreetype/src/raster/ftrend1.h | 2 +- .../native/libfreetype/src/raster/rasterrs.h | 2 +- .../native/libfreetype/src/sfnt/pngshim.c | 2 +- .../native/libfreetype/src/sfnt/pngshim.h | 2 +- .../native/libfreetype/src/sfnt/sfdriver.c | 4 +- .../native/libfreetype/src/sfnt/sfdriver.h | 2 +- .../native/libfreetype/src/sfnt/sferrors.h | 2 +- .../native/libfreetype/src/sfnt/sfobjs.c | 9 +- .../native/libfreetype/src/sfnt/sfobjs.h | 2 +- .../native/libfreetype/src/sfnt/sfwoff.c | 2 +- .../native/libfreetype/src/sfnt/sfwoff.h | 2 +- .../native/libfreetype/src/sfnt/sfwoff2.c | 8 +- .../native/libfreetype/src/sfnt/sfwoff2.h | 2 +- .../native/libfreetype/src/sfnt/ttcmap.c | 22 +- .../native/libfreetype/src/sfnt/ttcmap.h | 2 +- .../native/libfreetype/src/sfnt/ttcmapc.h | 2 +- .../native/libfreetype/src/sfnt/ttcolr.c | 4 +- .../native/libfreetype/src/sfnt/ttcolr.h | 2 +- .../native/libfreetype/src/sfnt/ttcpal.c | 2 +- .../native/libfreetype/src/sfnt/ttcpal.h | 2 +- .../native/libfreetype/src/sfnt/ttkern.c | 5 +- .../native/libfreetype/src/sfnt/ttkern.h | 8 +- .../native/libfreetype/src/sfnt/ttload.c | 32 +- .../native/libfreetype/src/sfnt/ttload.h | 2 +- .../share/native/libfreetype/src/sfnt/ttmtx.c | 4 +- .../share/native/libfreetype/src/sfnt/ttmtx.h | 2 +- .../native/libfreetype/src/sfnt/ttpost.c | 2 +- .../native/libfreetype/src/sfnt/ttpost.h | 2 +- .../native/libfreetype/src/sfnt/ttsbit.c | 55 +- .../native/libfreetype/src/sfnt/ttsbit.h | 2 +- .../native/libfreetype/src/sfnt/woff2tags.c | 2 +- .../native/libfreetype/src/sfnt/woff2tags.h | 2 +- .../native/libfreetype/src/smooth/ftgrays.c | 84 +- .../native/libfreetype/src/smooth/ftgrays.h | 13 +- .../native/libfreetype/src/smooth/ftsmerrs.h | 2 +- .../native/libfreetype/src/smooth/ftsmooth.c | 2 +- .../native/libfreetype/src/smooth/ftsmooth.h | 2 +- .../libfreetype/src/truetype/ttdriver.c | 6 +- .../libfreetype/src/truetype/ttdriver.h | 2 +- .../libfreetype/src/truetype/tterrors.h | 2 +- .../native/libfreetype/src/truetype/ttgload.c | 423 ++--- .../native/libfreetype/src/truetype/ttgload.h | 2 +- .../native/libfreetype/src/truetype/ttgxvar.c | 702 +++++-- .../native/libfreetype/src/truetype/ttgxvar.h | 7 +- .../libfreetype/src/truetype/ttinterp.c | 1587 +++++++--------- .../libfreetype/src/truetype/ttinterp.h | 128 +- .../native/libfreetype/src/truetype/ttobjs.c | 450 ++--- .../native/libfreetype/src/truetype/ttobjs.h | 127 +- .../native/libfreetype/src/truetype/ttpload.c | 18 +- .../native/libfreetype/src/truetype/ttpload.h | 2 +- .../libfreetype/src/truetype/ttsubpix.c | 1013 ----------- .../libfreetype/src/truetype/ttsubpix.h | 110 -- .../native/libfreetype/src/type1/t1afm.c | 2 +- .../native/libfreetype/src/type1/t1afm.h | 2 +- .../native/libfreetype/src/type1/t1driver.c | 2 +- .../native/libfreetype/src/type1/t1driver.h | 2 +- .../native/libfreetype/src/type1/t1errors.h | 2 +- .../native/libfreetype/src/type1/t1gload.c | 44 +- .../native/libfreetype/src/type1/t1gload.h | 2 +- .../native/libfreetype/src/type1/t1load.c | 8 +- .../native/libfreetype/src/type1/t1load.h | 2 +- .../native/libfreetype/src/type1/t1objs.c | 2 +- .../native/libfreetype/src/type1/t1objs.h | 2 +- .../native/libfreetype/src/type1/t1parse.c | 2 +- .../native/libfreetype/src/type1/t1parse.h | 2 +- .../native/libfreetype/src/type1/t1tokens.h | 2 +- .../html/CSS/8231286/HtmlFontSizeTest.java | 18 +- 286 files changed, 7169 insertions(+), 4787 deletions(-) create mode 100644 src/java.desktop/share/native/libfreetype/src/autofit/afadjust.c create mode 100644 src/java.desktop/share/native/libfreetype/src/autofit/afadjust.h create mode 100644 src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.c create mode 100644 src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.h delete mode 100644 src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c delete mode 100644 src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h diff --git a/src/java.desktop/share/legal/freetype.md b/src/java.desktop/share/legal/freetype.md index 5df525e2f67..cf2518df594 100644 --- a/src/java.desktop/share/legal/freetype.md +++ b/src/java.desktop/share/legal/freetype.md @@ -1,4 +1,4 @@ -## The FreeType Project: Freetype v2.13.3 +## The FreeType Project: Freetype v2.14.1 ### FreeType Notice @@ -21,25 +21,24 @@ which fits your needs best. ### FreeType License ``` -Copyright (C) 1996-2024 by David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2007-2024 by Dereg Clegg and Michael Toftdal. -Copyright (C) 1996-2024 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2022-2024 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and -Copyright (C) 2004-2024 by Masatake YAMATO and Redhat K.K. -Copyright (C) 2007-2024 by Derek Clegg and Michael Toftdal. -Copyright (C) 2003-2024 by Masatake YAMATO, Red Hat K.K., -Copyright (C) 1996-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. -Copyright (C) 2007-2024 by David Turner. -Copyright (C) 2022-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. -Copyright (C) 2007-2024 by Rahul Bhalerao , . -Copyright (C) 2008-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. -Copyright (C) 2013-2024 by Google, Inc. -Copyright (C) 2019-2024 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. -Copyright (C) 2009-2024 by Oran Agra and Mickey Gabel. -Copyright (C) 2018-2024 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. -Copyright (C) 2004-2024 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. - - +Copyright (C) 1996-2025 by David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2007-2025 by Dereg Clegg and Michael Toftdal. +Copyright (C) 1996-2025 by Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2022-2025 by David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and +Copyright (C) 2004-2025 by Masatake YAMATO and Redhat K.K. +Copyright (C) 2007-2025 by Derek Clegg and Michael Toftdal. +Copyright (C) 2003-2025 by Masatake YAMATO, Red Hat K.K., +Copyright (C) 1996-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. +Copyright (C) 2007-2025 by David Turner. +Copyright (C) 2022-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. +Copyright (C) 2007-2025 by Rahul Bhalerao , . +Copyright (C) 2025 by Behdad Esfahbod. +Copyright (C) 2008-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. +Copyright (C) 2013-2025 by Google, Inc. +Copyright (C) 2019-2025 by Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright (C) 2009-2025 by Oran Agra and Mickey Gabel. +Copyright (C) 2018-2025 by David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. +Copyright (C) 2004-2025 by David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. The FreeType Project LICENSE ---------------------------- @@ -207,6 +206,7 @@ Legal Terms https://www.freetype.org + ``` ### GPL v2 diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h index 0667493fec6..d66c5df9976 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftconfig.h @@ -4,7 +4,7 @@ * * ANSI-specific configuration file (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h index f6ef2618ded..16eab9048fc 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftheader.h @@ -4,7 +4,7 @@ * * Build macros of the FreeType 2 library. * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h index d29a0a7cefb..be7a4c50dc3 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h @@ -4,7 +4,7 @@ * * User-selectable configuration macros (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -158,12 +158,12 @@ FT_BEGIN_HEADER /************************************************************************** * - * If this macro is defined, try to use an inlined assembler version of the - * @FT_MulFix function, which is a 'hotspot' when loading and hinting - * glyphs, and which should be executed as fast as possible. + * If this macro is defined, try to use an inlined 64-bit or assembler + * version of the @FT_MulFix function, which is a 'hotspot' when loading + * and hinting glyphs, and which should be executed as fast as possible. * - * Note that if your compiler or CPU is not supported, this will default to - * the standard and portable implementation found in `ftcalc.c`. + * If your compiler is not C99-compliant or CPU assembly is not supported, + * you can disable this option. */ #define FT_CONFIG_OPTION_INLINE_MULFIX @@ -293,6 +293,31 @@ FT_BEGIN_HEADER /* #define FT_CONFIG_OPTION_USE_HARFBUZZ */ + /************************************************************************** + * + * HarfBuzz dynamic support. + * + * Define this macro if you want the HarfBuzz library to be loaded at + * runtime instead of being linked to FreeType. + * + * This option has no effect if `FT_CONFIG_OPTION_USE_HARFBUZZ` is not + * defined. + * + * When this option is enabled, FreeType will try to load the HarfBuzz + * library at runtime, using `dlopen` or `LoadLibrary`, depending on the + * platform. On Microsoft platforms, the library name looked up is + * `libharfbuzz-0.dll`. On Apple platforms, the library name looked up + * is `libharfbuzz.0.dylib`. On all other platforms, the library name + * looked up is `libharfbuzz.so.0`. This name can be overridden by + * defining the macro `FT_LIBHARFBUZZ` at FreeType compilation time. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + + /************************************************************************** * * Brotli support. @@ -679,7 +704,7 @@ FT_BEGIN_HEADER * defined. * * [1] - * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + * https://learn.microsoft.com/typography/cleartype/truetypecleartype */ #define TT_CONFIG_OPTION_SUBPIXEL_HINTING @@ -697,7 +722,7 @@ FT_BEGIN_HEADER * flags array which can be used to disambiguate, but old fonts will not * have them. * - * https://www.microsoft.com/typography/otspec/glyf.htm + * https://learn.microsoft.com/typography/opentype/spec/glyf * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html */ #undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED @@ -760,10 +785,10 @@ FT_BEGIN_HEADER /************************************************************************** * * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning - * implementation (for TrueType fonts only). With this defined, FreeType - * is able to get kerning pair data from the GPOS 'kern' feature as well as - * legacy 'kern' tables; without this defined, FreeType will only be able - * to use legacy 'kern' tables. + * implementation (for TrueType and OpenType fonts only). With this + * defined, FreeType is able to get kerning pair data from the GPOS 'kern' + * feature as well as legacy 'kern' tables; without this defined, FreeType + * will only be able to use legacy 'kern' tables. * * Note that FreeType does not support more advanced GPOS layout features; * even the 'kern' feature implemented here doesn't handle more diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h index e17aa7b89d5..f846b4456c1 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftstdlib.h @@ -5,7 +5,7 @@ * ANSI-specific library and header configuration file (specification * only). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h index c27505ffc4b..a0b892ece4b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/integer-types.h @@ -4,7 +4,7 @@ * * FreeType integer types definitions. * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,6 +17,8 @@ #ifndef FREETYPE_CONFIG_INTEGER_TYPES_H_ #define FREETYPE_CONFIG_INTEGER_TYPES_H_ +FT_BEGIN_HEADER + /* There are systems (like the Texas Instruments 'C54x) where a `char` */ /* has 16~bits. ANSI~C says that `sizeof(char)` is always~1. Since an */ /* `int` has 16~bits also for this system, `sizeof(int)` gives~1 which */ @@ -242,9 +244,34 @@ #endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ #ifdef FT_INT64 + typedef FT_INT64 FT_Int64; typedef FT_UINT64 FT_UInt64; -#endif +# define FT_INT64_ZERO 0 + +#else /* !FT_INT64 */ + + /* we need to emulate 64-bit data types if none are available */ + + typedef struct FT_Int64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + + } FT_Int64; + + typedef struct FT_UInt64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + + } FT_UInt64; + +# define FT_INT64_ZERO { 0, 0 } + +#endif /* !FT_INT64 */ + +FT_END_HEADER #endif /* FREETYPE_CONFIG_INTEGER_TYPES_H_ */ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h index 07b6f915bd8..d1b6a9898fd 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/mac-support.h @@ -4,7 +4,7 @@ * * Mac/OS X support configuration header. * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h index f56581a6ee7..9f28b394737 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/public-macros.h @@ -4,7 +4,7 @@ * * Define a set of compiler macros used in public FreeType headers. * - * Copyright (C) 2020-2024 by + * Copyright (C) 2020-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -62,8 +62,8 @@ FT_BEGIN_HEADER * because it is needed by `FT_EXPORT`. */ - /* Visual C, mingw */ -#if defined( _WIN32 ) + /* Visual C, MinGW, Cygwin */ +#if defined( _WIN32 ) || defined( __CYGWIN__ ) #if defined( FT2_BUILD_LIBRARY ) && defined( DLL_EXPORT ) #define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllexport ) diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h index 58fc33dfe60..1e249235882 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h @@ -4,7 +4,7 @@ * * FreeType high-level API and common types (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -811,7 +811,7 @@ FT_BEGIN_HEADER * FT_ENCODING_MS_SYMBOL :: * Microsoft Symbol encoding, used to encode mathematical symbols and * wingdings. For more information, see - * 'https://www.microsoft.com/typography/otspec/recom.htm#non-standard-symbol-fonts', + * 'https://learn.microsoft.com/typography/opentype/spec/recom#non-standard-symbol-fonts', * 'http://www.kostis.net/charsets/symbol.htm', and * 'http://www.kostis.net/charsets/wingding.htm'. * @@ -1068,12 +1068,12 @@ FT_BEGIN_HEADER * the face in the font file (starting with value~0). They are set * to~0 if there is only one face in the font file. * - * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation - * fonts only, holding the named instance index for the current face - * index (starting with value~1; value~0 indicates font access without - * a named instance). For non-variation fonts, bits 16-30 are ignored. - * If we have the third named instance of face~4, say, `face_index` is - * set to 0x00030004. + * [Since 2.6.1] Bits 16-30 are relevant to TrueType GX and OpenType + * Font Variations only, holding the named instance index for the + * current face index (starting with value~1; value~0 indicates font + * access without a named instance). For non-variation fonts, bits + * 16-30 are ignored. If we have the third named instance of face~4, + * say, `face_index` is set to 0x00030004. * * Bit 31 is always zero (that is, `face_index` is always a positive * value). @@ -1092,10 +1092,10 @@ FT_BEGIN_HEADER * the face; see @FT_STYLE_FLAG_XXX for the details. * * [Since 2.6.1] Bits 16-30 hold the number of named instances - * available for the current face if we have a GX or OpenType variation - * (sub)font. Bit 31 is always zero (that is, `style_flags` is always - * a positive value). Note that a variation font has always at least - * one named instance, namely the default instance. + * available for the current face if we have a TrueType GX or OpenType + * Font Variation. Bit 31 is always zero (that is, `style_flags` is + * always a positive value). Note that a variation font has always at + * least one named instance, namely the default instance. * * num_glyphs :: * The number of glyphs in the face. If the face is scalable and has @@ -1159,7 +1159,7 @@ FT_BEGIN_HEADER * Note that the bounding box might be off by (at least) one pixel for * hinted fonts. See @FT_Size_Metrics for further discussion. * - * Note that the bounding box does not vary in OpenType variation fonts + * Note that the bounding box does not vary in OpenType Font Variations * and should only be used in relation to the default instance. * * units_per_EM :: @@ -1218,7 +1218,7 @@ FT_BEGIN_HEADER * Fields may be changed after a call to @FT_Attach_File or * @FT_Attach_Stream. * - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `ascender`, `descender`, `height`, * `underline_position`, and `underline_thickness`. @@ -1336,7 +1336,7 @@ FT_BEGIN_HEADER * FT_FACE_FLAG_MULTIPLE_MASTERS :: * The face contains multiple masters and is capable of interpolating * between them. Supported formats are Adobe MM, TrueType GX, and - * OpenType variation fonts. + * OpenType Font Variations. * * See section @multiple_masters for API details. * @@ -1609,7 +1609,7 @@ FT_BEGIN_HEADER * * @description: * A macro that returns true whenever a face object is a named instance - * of a GX or OpenType variation font. + * of a TrueType GX or OpenType Font Variations. * * [Since 2.9] Changing the design coordinates with * @FT_Set_Var_Design_Coordinates or @FT_Set_Var_Blend_Coordinates does @@ -2147,7 +2147,7 @@ FT_BEGIN_HEADER * freed. * * [Since 2.10.1] If @FT_LOAD_NO_SCALE is set, outline coordinates of - * OpenType variation fonts for a selected instance are internally + * OpenType Font Variations for a selected instance are internally * handled as 26.6 fractional font units but returned as (rounded) * integers, as expected. To get unrounded font units, don't use * @FT_LOAD_NO_SCALE but load the glyph with @FT_LOAD_NO_HINTING and @@ -2640,14 +2640,14 @@ FT_BEGIN_HEADER * the face in the font file (starting with value~0). Set it to~0 if * there is only one face in the font file. * - * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation - * fonts only, specifying the named instance index for the current face - * index (starting with value~1; value~0 makes FreeType ignore named - * instances). For non-variation fonts, bits 16-30 are ignored. - * Assuming that you want to access the third named instance in face~4, - * `face_index` should be set to 0x00030004. If you want to access - * face~4 without variation handling, simply set `face_index` to - * value~4. + * [Since 2.6.1] Bits 16-30 are relevant to TrueType GX and OpenType + * Font Variations only, specifying the named instance index for the + * current face index (starting with value~1; value~0 makes FreeType + * ignore named instances). For non-variation fonts, bits 16-30 are + * ignored. Assuming that you want to access the third named instance + * in face~4, `face_index` should be set to 0x00030004. If you want + * to access face~4 without variation handling, simply set + * `face_index` to value~4. * * `FT_Open_Face` and its siblings can be used to quickly check whether * the font format of a given font resource is supported by FreeType. @@ -2914,11 +2914,11 @@ FT_BEGIN_HEADER * of the available glyphs at a given ppem value is available. FreeType * silently uses outlines if there is no bitmap for a given glyph index. * - * For GX and OpenType variation fonts, a bitmap strike makes sense only - * if the default instance is active (that is, no glyph variation takes - * place); otherwise, FreeType simply ignores bitmap strikes. The same - * is true for all named instances that are different from the default - * instance. + * For TrueType GX and OpenType Font Variations, a bitmap strike makes + * sense only if the default instance is active (that is, no glyph + * variation takes place); otherwise, FreeType simply ignores bitmap + * strikes. The same is true for all named instances that are different + * from the default instance. * * Don't use this function if you are using the FreeType cache API. */ @@ -3078,7 +3078,7 @@ FT_BEGIN_HEADER * is dependent entirely on how the size is defined in the source face. * The font designer chooses the final size of each glyph relative to * this size. For more information refer to - * 'https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html'. + * 'https://freetype.org/freetype2/docs/glyphs/glyphs-2.html'. * * Contrary to @FT_Set_Char_Size, this function doesn't have special code * to normalize zero-valued widths, heights, or resolutions, which are @@ -3441,8 +3441,10 @@ FT_BEGIN_HEADER * blending of the color glyph layers associated with the glyph index, * using the same bitmap format as embedded color bitmap images. This * is mainly for convenience and works only for glyphs in 'COLR' v0 - * tables (or glyphs in 'COLR' v1 tables that exclusively use v0 - * features). For full control of color layers use + * tables. **There is no rendering support for 'COLR' v1** (with the + * exception of v1 tables that exclusively use v0 features)! You need + * a graphics library like Skia or Cairo to interpret the graphics + * commands stored in v1 tables. For full control of color layers use * @FT_Get_Color_Glyph_Layer and FreeType's color functions like * @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering * so that the client application can handle blending by itself. @@ -3895,8 +3897,10 @@ FT_BEGIN_HEADER * * This process can cost performance. There is an approximation that * does not need to know about the background color; see - * https://bel.fi/alankila/lcd/ and - * https://bel.fi/alankila/lcd/alpcor.html for details. + * https://web.archive.org/web/20211019204945/https://bel.fi/alankila/lcd/ + * and + * https://web.archive.org/web/20210211002939/https://bel.fi/alankila/lcd/alpcor.html + * for details. * * **ATTENTION**: Linear blending is even more important when dealing * with subpixel-rendered glyphs to prevent color-fringing! A @@ -3993,13 +3997,13 @@ FT_BEGIN_HEADER * out of the scope of this API function -- they can be implemented * through format-specific interfaces. * - * Note that, for TrueType fonts only, this can extract data from both - * the 'kern' table and the basic, pair-wise kerning feature from the - * GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though - * FreeType does not support the more advanced GPOS layout features; use - * a library like HarfBuzz for those instead. If a font has both a - * 'kern' table and kern features of a GPOS table, the 'kern' table will - * be used. + * Note that, for TrueType and OpenType fonts only, this can extract data + * from both the 'kern' table and the basic, pair-wise kerning feature + * from the GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), + * though FreeType does not support the more advanced GPOS layout + * features; use a library like HarfBuzz for those instead. If a font + * has both a 'kern' table and kern features of a GPOS table, the 'kern' + * table will be used. * * Also note for right-to-left scripts, the functionality may differ for * fonts with GPOS tables vs. 'kern' tables. For GPOS, right-to-left @@ -4530,7 +4534,7 @@ FT_BEGIN_HEADER * table description in the OpenType specification for the meaning of the * various flags (which get synthesized for non-OpenType subglyphs). * - * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * https://learn.microsoft.com/typography/opentype/spec/glyf#composite-glyph-description * * @values: * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: @@ -4593,7 +4597,7 @@ FT_BEGIN_HEADER * interpreted depending on the flags returned in `*p_flags`. See the * OpenType specification for details. * - * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * https://learn.microsoft.com/typography/opentype/spec/glyf#composite-glyph-description * */ FT_EXPORT( FT_Error ) @@ -4619,7 +4623,7 @@ FT_BEGIN_HEADER * associated with a font. * * See - * https://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/FontPolicies.pdf + * https://adobe-type-tools.github.io/font-tech-notes/pdfs/AcrobatDC_FontPolicies.pdf * for more details. * * @values: @@ -5173,8 +5177,8 @@ FT_BEGIN_HEADER * */ #define FREETYPE_MAJOR 2 -#define FREETYPE_MINOR 13 -#define FREETYPE_PATCH 3 +#define FREETYPE_MINOR 14 +#define FREETYPE_PATCH 1 /************************************************************************** diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h index 85b8ba2554b..62a856ccbd7 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftadvanc.h @@ -4,7 +4,7 @@ * * Quick computation of advance widths (specification only). * - * Copyright (C) 2008-2024 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h index 12bbfa63a62..348b4b3a268 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbbox.h @@ -4,7 +4,7 @@ * * FreeType exact bbox computation (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h index 6f63b0b1e78..faad25689c9 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbdf.h @@ -4,7 +4,7 @@ * * FreeType API for accessing BDF-specific strings (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h index df9d462652e..a22d43adf14 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftbitmap.h @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (specification). * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h index 96b2a90fc59..7cda8ff3f39 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftcid.h @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information (specification). * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * Dereg Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h index 420720ddf22..129b1a23fb0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftcolor.h @@ -4,7 +4,7 @@ * * FreeType's glyph color management (specification). * - * Copyright (C) 2018-2024 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -317,6 +317,15 @@ FT_BEGIN_HEADER * @description: * The functions described here allow access of colored glyph layer data * in OpenType's 'COLR' tables. + * + * Note that FreeType does *not* provide rendering in general of glyphs + * that use a 'COLR' table! While FreeType has very limited rendering + * support for 'COLR' v0 tables (without a possibility to change the + * color palette) via @FT_Render_Glyph, there is no such convenience + * code for 'COLR' v1 tables -- while it appears that v1 is simply an + * 'improved' version of v0, this is not the case: it is a completely + * different color font format, and you need a dedicated graphics + * library like Skia or Cairo to handle a v1 table's drawing commands. */ @@ -359,7 +368,7 @@ FT_BEGIN_HEADER * iteratively retrieve the colored glyph layers associated with the * current glyph slot. * - * https://docs.microsoft.com/en-us/typography/opentype/spec/colr + * https://learn.microsoft.com/typography/opentype/spec/colr * * The glyph layer data for a given glyph index, if present, provides an * alternative, multi-color glyph representation: Instead of rendering @@ -1518,7 +1527,7 @@ FT_BEGIN_HEADER * * @return: * Value~1 if a clip box is found. If no clip box is found or an error - * occured, value~0 is returned. + * occurred, value~0 is returned. * * @note: * To retrieve the clip box in font units, reset scale to units-per-em @@ -1646,7 +1655,7 @@ FT_BEGIN_HEADER * * @return: * Value~1 if everything is OK. Value~0 if no details can be found for - * this paint or any other error occured. + * this paint or any other error occurred. * * @since: * 2.13 diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h index 1b7f539f5e2..b65a06ab69b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftdriver.h @@ -4,7 +4,7 @@ * * FreeType API for controlling driver modules (specification only). * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -282,7 +282,7 @@ FT_BEGIN_HEADER * minimize hinting techniques that were problematic with the extra * resolution of ClearType; see * http://rastertragedy.com/RTRCh4.htm#Sec1 and - * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx. + * https://learn.microsoft.com/typography/cleartype/truetypecleartype. * This technique is not to be confused with ClearType compatible widths. * ClearType backward compatibility has no direct impact on changing * advance widths, but there might be an indirect impact on disabling @@ -784,7 +784,7 @@ FT_BEGIN_HEADER * * Details on subpixel hinting and some of the necessary tweaks can be * found in Greg Hitchcock's whitepaper at - * 'https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx'. + * 'https://learn.microsoft.com/typography/cleartype/truetypecleartype'. * Note that FreeType currently doesn't really 'subpixel hint' (6x1, 6x2, * or 6x5 supersampling) like discussed in the paper. Depending on the * chosen interpreter, it simply ignores instructions on vertical stems diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h b/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h index 710ca91bbdd..3e591bede8d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fterrdef.h @@ -4,7 +4,7 @@ * * FreeType error codes (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h b/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h index 27c0ece5c1c..eca494f90c0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fterrors.h @@ -4,7 +4,7 @@ * * FreeType error code handling (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h index 7c8b0874a81..5df82447d0e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftfntfmt.h @@ -4,7 +4,7 @@ * * Support functions for font formats. * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h index 30e5a9bf82b..77e5a7e7bfd 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftgasp.h @@ -4,7 +4,7 @@ * * Access of TrueType's 'gasp' table (specification). * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h index dc1eb8873ae..3691781cf52 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftglyph.h @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h index 9516dc030ac..e26c334c11a 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftgzip.h @@ -4,7 +4,7 @@ * * Gzip-compressed stream support. * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h index 2b4b4ac60ae..b0a0172ef4f 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h @@ -5,7 +5,7 @@ * FreeType glyph image formats and default raster interface * (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -267,6 +267,10 @@ FT_BEGIN_HEADER * *logical* one. For example, if @FT_Pixel_Mode is set to * `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the * physical one. + * + * An empty bitmap with a NULL `buffer` is valid, with `rows` and/or + * `pitch` also set to 0. Such bitmaps might be produced while rendering + * empty or degenerate outlines. */ typedef struct FT_Bitmap_ { @@ -439,7 +443,7 @@ FT_BEGIN_HEADER * rasterizer; see the `tags` field in @FT_Outline. * * Please refer to the description of the 'SCANTYPE' instruction in the - * [OpenType specification](https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions#scantype) + * [OpenType specification](https://learn.microsoft.com/typography/opentype/spec/tt_instructions#scantype) * how simple drop-outs, smart drop-outs, and stubs are defined. */ #define FT_OUTLINE_NONE 0x0 diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h index 816581b78eb..2233044754e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftincrem.h @@ -4,7 +4,7 @@ * * FreeType incremental loading (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h index 25274dc4ac2..a0a8e9da929 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlcdfil.h @@ -5,7 +5,7 @@ * FreeType API for color filtering of subpixel bitmap glyphs * (specification). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h index 972fbfa2fe4..14958b0ff37 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlist.h @@ -4,7 +4,7 @@ * * Generic list support for FreeType (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h index 1813cfc2c27..d155171136c 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftlogging.h @@ -4,7 +4,7 @@ * * Additional debugging APIs. * - * Copyright (C) 2020-2024 by + * Copyright (C) 2020-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h index e4efde33dd8..c5ac49101a4 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmac.h @@ -4,7 +4,7 @@ * * Additional Mac-specific API. * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h index 35ed039c89b..ff0bbab59f9 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmm.h @@ -2,9 +2,9 @@ * * ftmm.h * - * FreeType Multiple Master font interface (specification). + * FreeType variation font interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -37,24 +37,79 @@ FT_BEGIN_HEADER * multiple_masters * * @title: - * Multiple Masters + * OpenType Font Variations, TrueType GX, and Adobe MM Fonts * * @abstract: - * How to manage Multiple Masters fonts. + * How to manage variable fonts with multiple design axes. * * @description: - * The following types and functions are used to manage Multiple Master - * fonts, i.e., the selection of specific design instances by setting - * design axis coordinates. + * The following types and functions manage OpenType Font Variations, + * Adobe Multiple Master (MM) fonts, and Apple TrueType GX fonts. These + * formats have in common that they allow the selection of specific + * design instances by setting design coordinates for one or more axes + * like font weight or width. * - * Besides Adobe MM fonts, the interface supports Apple's TrueType GX and - * OpenType variation fonts. Some of the routines only work with Adobe - * MM fonts, others will work with all three types. They are similar - * enough that a consistent interface makes sense. + * For historical reasons there are two interfaces. The first, older one + * can be used with Adobe MM fonts only, and the second, newer one is a + * unified interface that handles all three font formats. However, some + * differences remain and are documented accordingly; in particular, + * Adobe MM fonts don't have named instances (see below). * - * For Adobe MM fonts, macro @FT_IS_SFNT returns false. For GX and - * OpenType variation fonts, it returns true. + * For Adobe MM fonts, macro @FT_IS_SFNT returns false. For TrueType GX + * and OpenType Font Variations, it returns true. * + * We use mostly the terminology of the OpenType standard. Here are some + * important technical terms. + * + * * A 'named instance' is a tuple of design coordinates that has a + * string ID (i.e., an index into the font's 'name' table) associated + * with it. The font can tell the user that, for example, + * [Weight=700,Width=110] is 'Bold'. Another name for 'named instance' + * is 'named style'. + * + * Adobe MM fonts don't have named instances. + * + * * The 'default instance' of a variation font is that instance for + * which the nth axis coordinate is equal to the nth default axis + * coordinate (i.e., `axis[n].def` as specified in the @FT_MM_Var + * structure), with~n covering all axes. In TrueType GX and OpenType + * Font Variations, the default instance is explicitly given. In Adobe + * MM fonts, the `WeightVector` entry as found in the font file is + * taken as the default instance. + * + * For TrueType GX and OpenType Font Variations, FreeType synthesizes + * a named instance for the default instance if the font does not + * contain such an entry. + * + * * 'Design coordinates' are the axis values found in a variation font + * file. Their meaning is specified by the font designer and the + * values are rather arbitrary. + * + * For example, the 'weight' axis in design coordinates might vary + * between 100 (thin) and 900 (heavy) in font~A, while font~B + * contains values between 400 (normal) and 800 (extra bold). + * + * * 'Normalized coordinates' are design coordinates mapped to a standard + * range; they are also called 'blend coordinates'. + * + * For TrueType GX and OpenType Font Variations, the range is [-1;1], + * with the minimum mapped to value~-1, the default mapped to + * value~0, and the maximum mapped to value~1, and all other + * coordinates mapped to intervening points. Please look up the + * [OpenType + * specification](https://learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview) + * on how this mapping works in detail. + * + * For Adobe MM fonts, this standard range is [0;1], with the minimum + * mapped to value~0 and the maximum mapped to value~1, and all other + * coordinates mapped to intervening points. Please look up [Adobe + * TechNote + * #5015](https://adobe-type-tools.github.io/font-tech-notes/pdfs/5015.Type1_Supp.pdf) + * on how this mapping works in detail. + * + * Assuming that the two fonts in the previous example are OpenType + * Font Variations, both font~A's [100;900] and font~B's [400;800] + * coordinate ranges get mapped to [-1;1]. */ @@ -64,14 +119,14 @@ FT_BEGIN_HEADER * T1_MAX_MM_XXX * * @description: - * Multiple Masters limits as defined in their specifications. + * Adobe MM font limits as defined in their specifications. * * @values: * T1_MAX_MM_AXIS :: - * The maximum number of Multiple Masters axes. + * The maximum number of Adobe MM font axes. * * T1_MAX_MM_DESIGNS :: - * The maximum number of Multiple Masters designs. + * The maximum number of Adobe MM font designs. * * T1_MAX_MM_MAP_POINTS :: * The maximum number of elements in a design map. @@ -88,11 +143,10 @@ FT_BEGIN_HEADER * FT_MM_Axis * * @description: - * A structure to model a given axis in design space for Multiple Masters - * fonts. + * A structure to model a given axis in design space for Adobe MM fonts. * - * This structure can't be used for TrueType GX or OpenType variation - * fonts. + * This structure can't be used with TrueType GX or OpenType Font + * Variations. * * @fields: * name :: @@ -119,17 +173,17 @@ FT_BEGIN_HEADER * FT_Multi_Master * * @description: - * A structure to model the axes and space of a Multiple Masters font. + * A structure to model the axes and space of an Adobe MM font. * - * This structure can't be used for TrueType GX or OpenType variation - * fonts. + * This structure can't be used with TrueType GX or OpenType Font + * Variations. * * @fields: * num_axis :: * Number of axes. Cannot exceed~4. * * num_designs :: - * Number of designs; should be normally 2^num_axis even though the + * Number of designs; should be normally `2^num_axis` even though the * Type~1 specification strangely allows for intermediate designs to be * present. This number cannot exceed~16. * @@ -151,13 +205,13 @@ FT_BEGIN_HEADER * FT_Var_Axis * * @description: - * A structure to model a given axis in design space for Multiple - * Masters, TrueType GX, and OpenType variation fonts. + * A structure to model a given axis in design space for Adobe MM fonts, + * TrueType GX, and OpenType Font Variations. * * @fields: * name :: * The axis's name. Not always meaningful for TrueType GX or OpenType - * variation fonts. + * Font Variations. * * minimum :: * The axis's minimum design coordinate. @@ -171,17 +225,17 @@ FT_BEGIN_HEADER * * tag :: * The axis's tag (the equivalent to 'name' for TrueType GX and - * OpenType variation fonts). FreeType provides default values for + * OpenType Font Variations). FreeType provides default values for * Adobe MM fonts if possible. * * strid :: * The axis name entry in the font's 'name' table. This is another * (and often better) version of the 'name' field for TrueType GX or - * OpenType variation fonts. Not meaningful for Adobe MM fonts. + * OpenType Font Variations. Not meaningful for Adobe MM fonts. * * @note: * The fields `minimum`, `def`, and `maximum` are 16.16 fractional values - * for TrueType GX and OpenType variation fonts. For Adobe MM fonts, the + * for TrueType GX and OpenType Font Variations. For Adobe MM fonts, the * values are whole numbers (i.e., the fractional part is zero). */ typedef struct FT_Var_Axis_ @@ -205,7 +259,7 @@ FT_BEGIN_HEADER * * @description: * A structure to model a named instance in a TrueType GX or OpenType - * variation font. + * Font Variations. * * This structure can't be used for Adobe MM fonts. * @@ -215,11 +269,11 @@ FT_BEGIN_HEADER * entry for each axis. * * strid :: - * The entry in 'name' table identifying this instance. + * An index into the 'name' table identifying this instance. * * psid :: - * The entry in 'name' table identifying a PostScript name for this - * instance. Value 0xFFFF indicates a missing entry. + * An index into the 'name' table identifying a PostScript name for + * this instance. Value 0xFFFF indicates a missing entry. */ typedef struct FT_Var_Named_Style_ { @@ -236,39 +290,33 @@ FT_BEGIN_HEADER * FT_MM_Var * * @description: - * A structure to model the axes and space of an Adobe MM, TrueType GX, - * or OpenType variation font. + * A structure to model the axes and space of Adobe MM fonts, TrueType + * GX, or OpenType Font Variations. * * Some fields are specific to one format and not to the others. * * @fields: * num_axis :: * The number of axes. The maximum value is~4 for Adobe MM fonts; no - * limit in TrueType GX or OpenType variation fonts. + * limit in TrueType GX or OpenType Font Variations. * * num_designs :: - * The number of designs; should be normally 2^num_axis for Adobe MM - * fonts. Not meaningful for TrueType GX or OpenType variation fonts + * The number of designs; should be normally `2^num_axis` for Adobe MM + * fonts. Not meaningful for TrueType GX or OpenType Font Variations * (where every glyph could have a different number of designs). * * num_namedstyles :: - * The number of named styles; a 'named style' is a tuple of design - * coordinates that has a string ID (in the 'name' table) associated - * with it. The font can tell the user that, for example, - * [Weight=1.5,Width=1.1] is 'Bold'. Another name for 'named style' is - * 'named instance'. - * - * For Adobe Multiple Masters fonts, this value is always zero because - * the format does not support named styles. + * The number of named instances. For Adobe MM fonts, this value is + * always zero. * * axis :: - * An axis descriptor table. TrueType GX and OpenType variation fonts + * An axis descriptor table. TrueType GX and OpenType Font Variations * contain slightly more data than Adobe MM fonts. Memory management * of this pointer is done internally by FreeType. * * namedstyle :: - * A named style (instance) table. Only meaningful for TrueType GX and - * OpenType variation fonts. Memory management of this pointer is done + * An array of named instances. Only meaningful for TrueType GX and + * OpenType Font Variations. Memory management of this pointer is done * internally by FreeType. */ typedef struct FT_MM_Var_ @@ -290,8 +338,8 @@ FT_BEGIN_HEADER * @description: * Retrieve a variation descriptor of a given Adobe MM font. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @input: * face :: @@ -299,7 +347,7 @@ FT_BEGIN_HEADER * * @output: * amaster :: - * The Multiple Masters descriptor. + * The Adobe MM font's variation descriptor. * * @return: * FreeType error code. 0~means success. @@ -366,8 +414,8 @@ FT_BEGIN_HEADER * For Adobe MM fonts, choose an interpolated font design through design * coordinates. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @inout: * face :: @@ -391,8 +439,8 @@ FT_BEGIN_HEADER * * [Since 2.9] If `num_coords` is larger than zero, this function sets * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field - * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, - * this bit flag gets unset. + * (i.e., @FT_IS_VARIATION returns true). If `num_coords` is zero, this + * bit flag gets unset. */ FT_EXPORT( FT_Error ) FT_Set_MM_Design_Coordinates( FT_Face face, @@ -428,7 +476,7 @@ FT_BEGIN_HEADER * * @note: * The design coordinates are 16.16 fractional values for TrueType GX and - * OpenType variation fonts. For Adobe MM fonts, the values are supposed + * OpenType Font Variations. For Adobe MM fonts, the values are supposed * to be whole numbers (i.e., the fractional part is zero). * * [Since 2.8.1] To reset all axes to the default values, call the @@ -438,8 +486,14 @@ FT_BEGIN_HEADER * * [Since 2.9] If `num_coords` is larger than zero, this function sets * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field - * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, - * this bit flag gets unset. + * (i.e., @FT_IS_VARIATION returns true). If `num_coords` is zero, this + * bit flag gets unset. + * + * [Since 2.14] This function also sets the @FT_FACE_FLAG_VARIATION bit + * in @FT_Face's `face_flags` field (i.e., @FT_IS_VARIATION returns + * true) if any of the provided coordinates is different from the face's + * default value for the corresponding axis, that is, the set up face is + * not at its default position. */ FT_EXPORT( FT_Error ) FT_Set_Var_Design_Coordinates( FT_Face face, @@ -468,14 +522,14 @@ FT_BEGIN_HEADER * * @output: * coords :: - * The design coordinates array. + * The design coordinates array, which must be allocated by the user. * * @return: * FreeType error code. 0~means success. * * @note: * The design coordinates are 16.16 fractional values for TrueType GX and - * OpenType variation fonts. For Adobe MM fonts, the values are whole + * OpenType Font Variations. For Adobe MM fonts, the values are whole * numbers (i.e., the fractional part is zero). * * @since: @@ -493,8 +547,7 @@ FT_BEGIN_HEADER * FT_Set_MM_Blend_Coordinates * * @description: - * Choose an interpolated font design through normalized blend - * coordinates. + * Choose an interpolated font design through normalized coordinates. * * This function works with all supported variation formats. * @@ -509,9 +562,10 @@ FT_BEGIN_HEADER * the number of axes, use default values for the remaining axes. * * coords :: - * The design coordinates array. Each element is a 16.16 fractional - * value and must be between 0 and 1.0 for Adobe MM fonts, and between - * -1.0 and 1.0 for TrueType GX and OpenType variation fonts. + * The normalized coordinates array. Each element is a 16.16 + * fractional value and must be between 0 and 1.0 for Adobe MM fonts, + * and between -1.0 and 1.0 for TrueType GX and OpenType Font + * Variations. * * @return: * FreeType error code. 0~means success. @@ -524,8 +578,14 @@ FT_BEGIN_HEADER * * [Since 2.9] If `num_coords` is larger than zero, this function sets * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field - * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, - * this bit flag gets unset. + * (i.e., @FT_IS_VARIATION returns true). If `num_coords` is zero, this + * bit flag gets unset. + * + * [Since 2.14] This function also sets the @FT_FACE_FLAG_VARIATION bit + * in @FT_Face's `face_flags` field (i.e., @FT_IS_VARIATION returns + * true) if any of the provided coordinates is different from the face's + * default value for the corresponding axis, that is, the set up face is + * not at its default position. */ FT_EXPORT( FT_Error ) FT_Set_MM_Blend_Coordinates( FT_Face face, @@ -539,8 +599,8 @@ FT_BEGIN_HEADER * FT_Get_MM_Blend_Coordinates * * @description: - * Get the normalized blend coordinates of the currently selected - * interpolated font. + * Get the normalized coordinates of the currently selected interpolated + * font. * * This function works with all supported variation formats. * @@ -549,14 +609,14 @@ FT_BEGIN_HEADER * A handle to the source face. * * num_coords :: - * The number of normalized blend coordinates to retrieve. If it is - * larger than the number of axes, set the excess values to~0.5 for - * Adobe MM fonts, and to~0 for TrueType GX and OpenType variation - * fonts. + * The number of normalized coordinates to retrieve. If it is larger + * than the number of axes, set the excess values to~0.5 for Adobe MM + * fonts, and to~0 for TrueType GX and OpenType Font Variations. * * @output: * coords :: - * The normalized blend coordinates array (as 16.16 fractional values). + * The normalized coordinates array (as 16.16 fractional values), which + * must be allocated by the user. * * @return: * FreeType error code. 0~means success. @@ -610,8 +670,8 @@ FT_BEGIN_HEADER * For Adobe MM fonts, choose an interpolated font design by directly * setting the weight vector. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @inout: * face :: @@ -630,16 +690,16 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * Adobe Multiple Master fonts limit the number of designs, and thus the - * length of the weight vector to 16~elements. + * Adobe MM fonts limit the number of designs, and thus the length of the + * weight vector, to 16~elements. * * If `len` is larger than zero, this function sets the * @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e., - * @FT_IS_VARIATION will return true). If `len` is zero, this bit flag - * is unset and the weight vector array is reset to the default values. + * @FT_IS_VARIATION returns true). If `len` is zero, this bit flag is + * unset and the weight vector array is reset to the default values. * * The Adobe documentation also states that the values in the - * WeightVector array must total 1.0 +/-~0.001. In practice this does + * `WeightVector` array must total 1.0 +/-~0.001. In practice this does * not seem to be enforced, so is not enforced here, either. * * @since: @@ -659,8 +719,8 @@ FT_BEGIN_HEADER * @description: * For Adobe MM fonts, retrieve the current weight vector of the font. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @inout: * face :: @@ -677,14 +737,14 @@ FT_BEGIN_HEADER * * @output: * weightvector :: - * An array to be filled. + * An array to be filled; it must be allocated by the user. * * @return: * FreeType error code. 0~means success. * * @note: - * Adobe Multiple Master fonts limit the number of designs, and thus the - * length of the WeightVector to~16. + * Adobe MM fonts limit the number of designs, and thus the length of the + * weight vector, to~16 elements. * * @since: * 2.10 @@ -760,8 +820,8 @@ FT_BEGIN_HEADER * A handle to the source face. * * instance_index :: - * The index of the requested instance, starting with value 1. If set - * to value 0, FreeType switches to font access without a named + * The index of the requested instance, starting with value~1. If set + * to value~0, FreeType switches to font access without a named * instance. * * @return: @@ -771,11 +831,11 @@ FT_BEGIN_HEADER * The function uses the value of `instance_index` to set bits 16-30 of * the face's `face_index` field. It also resets any variation applied * to the font, and the @FT_FACE_FLAG_VARIATION bit of the face's - * `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION will - * return false). + * `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION returns + * false). * - * For Adobe MM fonts (which don't have named instances) this function - * simply resets the current face to the default instance. + * For Adobe MM fonts, this function resets the current face to the + * default instance. * * @since: * 2.9 @@ -794,10 +854,6 @@ FT_BEGIN_HEADER * Retrieve the index of the default named instance, to be used with * @FT_Set_Named_Instance. * - * The default instance of a variation font is that instance for which - * the nth axis coordinate is equal to `axis[n].def` (as specified in the - * @FT_MM_Var structure), with~n covering all axes. - * * FreeType synthesizes a named instance for the default instance if the * font does not contain such an entry. * @@ -813,8 +869,8 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * For Adobe MM fonts (which don't have named instances) this function - * always returns zero for `instance_index`. + * For Adobe MM fonts, this function always returns zero for + * `instance_index`. * * @since: * 2.13.1 diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h index 0ee715898f7..2669e4a03b3 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmodapi.h @@ -4,7 +4,7 @@ * * FreeType modules public interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h index 6722fbf8b70..8e2ef2f01f8 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h @@ -4,7 +4,7 @@ * * FreeType module error offsets (specification). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h index 44e94b4f5bb..2545ca8486b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftoutln.h @@ -5,7 +5,7 @@ * Support for the FT_Outline type used to store glyph shapes of * most scalable font formats (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h index 43bf69c202f..2c09db1683e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftparams.h @@ -4,7 +4,7 @@ * * FreeType API for possible FT_Parameter tags (specification only). * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h index dc5018a1b54..cc3102073b1 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftrender.h @@ -4,7 +4,7 @@ * * FreeType renderer modules public interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h index 4ef5c7955df..fdb89f24ccc 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsizes.h @@ -4,7 +4,7 @@ * * FreeType size objects management (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h index d5d5cd93103..99728574db6 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsnames.h @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h index 41626dc9d7b..2c4761c768d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftstroke.h @@ -4,7 +4,7 @@ * * FreeType path stroker (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h index 43081b6c330..93499a4b4f1 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsynth.h @@ -5,7 +5,7 @@ * FreeType synthesizing code for emboldening and slanting * (specification). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h index 1eacb3af398..1de9f8e603d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftsystem.h @@ -4,7 +4,7 @@ * * FreeType low-level system interface definition (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h b/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h index a5299e938d4..ed7bd06a78f 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fttrigon.h @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (specification). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h index 27815143a64..e207c5ebe09 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h @@ -4,7 +4,7 @@ * * FreeType simple types definitions (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h index 8865d53b389..987e704e9b0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/autohint.h @@ -4,7 +4,7 @@ * * High-level 'autohint' module-specific interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h index 36b0390a5a5..26ee43bb9a9 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cffotypes.h @@ -4,7 +4,7 @@ * * Basic OpenType/CFF object type definitions (specification). * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h index ef2e8e7569c..62335db4834 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/cfftypes.h @@ -5,7 +5,7 @@ * Basic OpenType/CFF type definitions and interface (specification * only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h index 876f66e2561..e6d0166d888 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/compiler-macros.h @@ -4,7 +4,7 @@ * * Compiler-specific macro definitions used internally by FreeType. * - * Copyright (C) 2020-2024 by + * Copyright (C) 2020-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -128,8 +128,8 @@ FT_BEGIN_HEADER * before a function declaration. */ - /* Visual C, mingw */ -#if defined( _WIN32 ) + /* Visual C, MinGW, Cygwin */ +#if defined( _WIN32 ) || defined( __CYGWIN__ ) #define FT_INTERNAL_FUNCTION_ATTRIBUTE /* empty */ /* gcc, clang */ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h index 71128a2df90..16a732224ef 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h @@ -4,7 +4,7 @@ * * Arithmetic computations (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -27,17 +27,87 @@ FT_BEGIN_HEADER + /* + * The following macros have two purposes. + * + * - Tag places where overflow is expected and harmless. + * + * - Avoid run-time undefined behavior sanitizer errors. + * + * Use with care! + */ +#define ADD_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) ) +#define SUB_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) ) +#define MUL_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) ) +#define NEG_INT( a ) \ + (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) ) + +#define ADD_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) ) +#define SUB_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) ) +#define MUL_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) ) +#define NEG_LONG( a ) \ + (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) ) + +#define ADD_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) ) +#define SUB_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) ) +#define MUL_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) ) +#define NEG_INT32( a ) \ + (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) ) + +#ifdef FT_INT64 + +#define ADD_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) ) +#define SUB_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) ) +#define MUL_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) ) +#define NEG_INT64( a ) \ + (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) ) + +#endif /* FT_INT64 */ + + /************************************************************************** * * FT_MulDiv() and FT_MulFix() are declared in freetype.h. * */ -#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER - /* Provide assembler fragments for performance-critical functions. */ - /* These must be defined `static __inline__' with GCC. */ +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX -#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ +#ifdef FT_INT64 + + static inline FT_Long + FT_MulFix_64( FT_Long a, + FT_Long b ) + { + FT_Int64 ab = MUL_INT64( a, b ); + + + ab = ADD_INT64( ab, 0x8000 + ( ab >> 63 ) ); /* rounding phase */ + + return (FT_Long)( ab >> 16 ); + } + + +#define FT_MulFix( a, b ) FT_MulFix_64( a, b ) + +#elif !defined( FT_CONFIG_OPTION_NO_ASSEMBLER ) + /* Provide 32-bit assembler fragments for optimized FT_MulFix. */ + /* These must be defined `static __inline__' or similar. */ + +#if defined( __arm__ ) && \ + ( defined( __thumb2__ ) || !defined( __thumb__ ) ) #define FT_MULFIX_ASSEMBLER FT_MulFix_arm @@ -49,6 +119,7 @@ FT_BEGIN_HEADER { FT_Int32 t, t2; +#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ __asm { @@ -60,28 +131,8 @@ FT_BEGIN_HEADER mov a, t2, lsr #16 /* a = t2 >> 16 */ orr a, a, t, lsl #16 /* a |= t << 16 */ } - return a; - } - -#endif /* __CC_ARM || __ARMCC__ */ - - -#ifdef __GNUC__ - -#if defined( __arm__ ) && \ - ( !defined( __thumb__ ) || defined( __thumb2__ ) ) && \ - !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) - -#define FT_MULFIX_ASSEMBLER FT_MulFix_arm - - /* documentation is in freetype.h */ - - static __inline__ FT_Int32 - FT_MulFix_arm( FT_Int32 a, - FT_Int32 b ) - { - FT_Int32 t, t2; +#elif defined( __GNUC__ ) __asm__ __volatile__ ( "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ @@ -98,26 +149,25 @@ FT_BEGIN_HEADER : "=r"(a), "=&r"(t2), "=&r"(t) : "r"(a), "r"(b) : "cc" ); + +#endif + return a; } -#endif /* __arm__ && */ - /* ( __thumb2__ || !__thumb__ ) && */ - /* !( __CC_ARM || __ARMCC__ ) */ - - -#if defined( __i386__ ) +#elif defined( __i386__ ) || defined( _M_IX86 ) #define FT_MULFIX_ASSEMBLER FT_MulFix_i386 /* documentation is in freetype.h */ - static __inline__ FT_Int32 + static __inline FT_Int32 FT_MulFix_i386( FT_Int32 a, FT_Int32 b ) { FT_Int32 result; +#if defined( __GNUC__ ) __asm__ __volatile__ ( "imul %%edx\n" @@ -132,27 +182,8 @@ FT_BEGIN_HEADER : "=a"(result), "=d"(b) : "a"(a), "d"(b) : "%ecx", "cc" ); - return result; - } -#endif /* i386 */ - -#endif /* __GNUC__ */ - - -#ifdef _MSC_VER /* Visual C++ */ - -#ifdef _M_IX86 - -#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 - - /* documentation is in freetype.h */ - - static __inline FT_Int32 - FT_MulFix_i386( FT_Int32 a, - FT_Int32 b ) - { - FT_Int32 result; +#elif defined( _MSC_VER ) __asm { @@ -169,81 +200,21 @@ FT_BEGIN_HEADER add eax, edx mov result, eax } + +#endif + return result; } -#endif /* _M_IX86 */ +#endif /* __i386__ || _M_IX86 */ -#endif /* _MSC_VER */ - - -#if defined( __GNUC__ ) && defined( __x86_64__ ) - -#define FT_MULFIX_ASSEMBLER FT_MulFix_x86_64 - - static __inline__ FT_Int32 - FT_MulFix_x86_64( FT_Int32 a, - FT_Int32 b ) - { - /* Temporarily disable the warning that C90 doesn't support */ - /* `long long'. */ -#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wlong-long" -#endif - -#if 1 - /* Technically not an assembly fragment, but GCC does a really good */ - /* job at inlining it and generating good machine code for it. */ - long long ret, tmp; - - - ret = (long long)a * b; - tmp = ret >> 63; - ret += 0x8000 + tmp; - - return (FT_Int32)( ret >> 16 ); -#else - - /* For some reason, GCC 4.6 on Ubuntu 12.04 generates invalid machine */ - /* code from the lines below. The main issue is that `wide_a' is not */ - /* properly initialized by sign-extending `a'. Instead, the generated */ - /* machine code assumes that the register that contains `a' on input */ - /* can be used directly as a 64-bit value, which is wrong most of the */ - /* time. */ - long long wide_a = (long long)a; - long long wide_b = (long long)b; - long long result; - - - __asm__ __volatile__ ( - "imul %2, %1\n" - "mov %1, %0\n" - "sar $63, %0\n" - "lea 0x8000(%1, %0), %0\n" - "sar $16, %0\n" - : "=&r"(result), "=&r"(wide_a) - : "r"(wide_b) - : "cc" ); - - return (FT_Int32)result; -#endif - -#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) -#pragma GCC diagnostic pop -#endif - } - -#endif /* __GNUC__ && __x86_64__ */ - -#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ - - -#ifdef FT_CONFIG_OPTION_INLINE_MULFIX #ifdef FT_MULFIX_ASSEMBLER #define FT_MulFix( a, b ) FT_MULFIX_ASSEMBLER( (FT_Int32)(a), (FT_Int32)(b) ) #endif -#endif + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + +#endif /* FT_CONFIG_OPTION_INLINE_MULFIX */ /************************************************************************** @@ -278,40 +249,6 @@ FT_BEGIN_HEADER FT_Long c ); - /************************************************************************** - * - * @function: - * FT_MulAddFix - * - * @description: - * Compute `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`, where `s[n]` is - * usually a 16.16 scalar. - * - * @input: - * s :: - * The array of scalars. - * f :: - * The array of factors. - * count :: - * The number of entries in the array. - * - * @return: - * The result of `(s[0] * f[0] + s[1] * f[1] + ...) / 0x10000`. - * - * @note: - * This function is currently used for the scaled delta computation of - * variation stores. It internally uses 64-bit data types when - * available, otherwise it emulates 64-bit math by using 32-bit - * operations, which produce a correct result but most likely at a slower - * performance in comparison to the implementation base on `int64_t`. - * - */ - FT_BASE( FT_Int32 ) - FT_MulAddFix( FT_Fixed* s, - FT_Int32* f, - FT_UInt count ); - - /* * A variant of FT_Matrix_Multiply which scales its result afterwards. The * idea is that both `a' and `b' are scaled by factors of 10 so that the @@ -455,6 +392,10 @@ FT_BEGIN_HEADER #define FT_MSB( x ) FT_MSB_i386( x ) +#elif defined( __CC_ARM ) + +#define FT_MSB( x ) ( 31 - __clz( x ) ) + #elif defined( __SunOS_5_11 ) #include @@ -526,55 +467,6 @@ FT_BEGIN_HEADER #define ROUND_F26DOT6( x ) ( ( (x) + 32 - ( x < 0 ) ) & -64 ) - /* - * The following macros have two purposes. - * - * - Tag places where overflow is expected and harmless. - * - * - Avoid run-time sanitizer errors. - * - * Use with care! - */ -#define ADD_INT( a, b ) \ - (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) ) -#define SUB_INT( a, b ) \ - (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) ) -#define MUL_INT( a, b ) \ - (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) ) -#define NEG_INT( a ) \ - (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) ) - -#define ADD_LONG( a, b ) \ - (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) ) -#define SUB_LONG( a, b ) \ - (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) ) -#define MUL_LONG( a, b ) \ - (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) ) -#define NEG_LONG( a ) \ - (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) ) - -#define ADD_INT32( a, b ) \ - (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) ) -#define SUB_INT32( a, b ) \ - (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) ) -#define MUL_INT32( a, b ) \ - (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) ) -#define NEG_INT32( a ) \ - (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) ) - -#ifdef FT_INT64 - -#define ADD_INT64( a, b ) \ - (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) ) -#define SUB_INT64( a, b ) \ - (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) ) -#define MUL_INT64( a, b ) \ - (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) ) -#define NEG_INT64( a ) \ - (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) ) - -#endif /* FT_INT64 */ - FT_END_HEADER diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h index d7fa8dc93cf..d7facf40d12 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h @@ -4,7 +4,7 @@ * * Debugging and logging component (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h index 5609b3ef12b..24be4dad36b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdrv.h @@ -4,7 +4,7 @@ * * FreeType internal font driver interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h index f1c155b162c..8f2a54c015b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftgloadr.h @@ -4,7 +4,7 @@ * * The FreeType glyph loader (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h index 622ec76bb9a..642d21e21c6 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fthash.h @@ -117,6 +117,18 @@ FT_BEGIN_HEADER FT_Hash hash, FT_Memory memory ); + FT_Error + ft_hash_str_insert_no_overwrite( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ); + + FT_Error + ft_hash_num_insert_no_overwrite( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ); + size_t* ft_hash_str_lookup( const char* key, FT_Hash hash ); @@ -125,6 +137,17 @@ FT_BEGIN_HEADER ft_hash_num_lookup( FT_Int num, FT_Hash hash ); + FT_Bool + ft_hash_num_iterator( FT_UInt *idx, + FT_Int *key, + size_t *value, + FT_Hash hash ); + + FT_Bool + ft_hash_str_iterator( FT_UInt *idx, + const char* *key, + size_t *value, + FT_Hash hash ); FT_END_HEADER diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h index 4e05a29f13a..c75c33f2895 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmemory.h @@ -4,7 +4,7 @@ * * The FreeType memory management macros (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h index 8449e7a010d..be3747bbf94 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h @@ -5,7 +5,7 @@ * OpenType Variations type definitions for internal use * with the multi-masters service (specification). * - * Copyright (C) 2022-2024 by + * Copyright (C) 2022-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and * Dominik Röttsches. * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h index a1e93298fdb..3db2fe28ffd 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h @@ -4,7 +4,7 @@ * * The FreeType private base classes (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -275,6 +275,28 @@ FT_BEGIN_HEADER FT_GlyphSlot slot, FT_Render_Mode mode ); + + /************************************************************************** + * + * @Function: + * find_unicode_charmap + * + * @Description: + * This function finds a Unicode charmap, if there is one. And if there + * is more than one, it tries to favour the more extensive one, i.e., one + * that supports UCS-4 against those which are limited to the BMP (UCS-2 + * encoding.) + * + * If a unicode charmap is found, `face->charmap` is set to it. + * + * This function is called from `open_face`, from `FT_Select_Charmap(..., + * FT_ENCODING_UNICODE)`, and also from `afadjust.c` in the 'autofit' + * module. + */ + FT_BASE( FT_Error ) + find_unicode_charmap( FT_Face face ); + + #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, @@ -498,9 +520,9 @@ FT_BEGIN_HEADER */ typedef struct FT_ModuleRec_ { - FT_Module_Class* clazz; - FT_Library library; - FT_Memory memory; + const FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; } FT_ModuleRec; diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h index 4f11aa16ba1..18a954d22f5 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftpsprop.h @@ -4,7 +4,7 @@ * * Get and set properties of PostScript drivers (specification). * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h index 05c1d6c48b5..e077f98bfb9 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftrfork.h @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (specification). * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * Masatake YAMATO and Redhat K.K. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h index 8c35dbd7139..ce11bba19b2 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h @@ -4,7 +4,7 @@ * * The FreeType services (specification only). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h index fd52f767ef7..20c1dd7c4b0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftstream.h @@ -4,7 +4,7 @@ * * Stream handling (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h index 42595a29ff3..3fd592800e2 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h @@ -4,7 +4,7 @@ * * Tracing handling (specification only). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ /* definitions of trace levels for FreeType 2 */ /* the maximum string length (if the argument to `FT_TRACE_DEF` */ - /* gets used as a string) plus one charachter for ':' plus */ + /* gets used as a string) plus one character for ':' plus */ /* another one for the trace level */ #define FT_MAX_TRACE_LEVEL_LENGTH (9 + 1 + 1) @@ -159,6 +159,7 @@ FT_TRACE_DEF( gxvprop ) FT_TRACE_DEF( gxvtrak ) /* autofit components */ +FT_TRACE_DEF( afadjust ) FT_TRACE_DEF( afcjk ) FT_TRACE_DEF( afglobal ) FT_TRACE_DEF( afhints ) diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h index a1312f2aba6..03a726c82cb 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftvalid.h @@ -4,7 +4,7 @@ * * FreeType validation support (specification). * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h index 745d2cb56b7..344be0f19a7 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/psaux.h @@ -5,7 +5,7 @@ * Auxiliary functions and data structures related to PostScript fonts * (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h index dba6c7303fd..96c5d84f058 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/pshints.h @@ -6,7 +6,7 @@ * recorders (specification only). These are used to support native * T1/T2 hints in the 'type1', 'cid', and 'cff' font drivers. * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h index 89e9c2e5de8..5bd51da23f4 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svbdf.h @@ -4,7 +4,7 @@ * * The FreeType BDF services (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h index 3cb483c344f..c97bf84fb2e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcfftl.h @@ -4,7 +4,7 @@ * * The FreeType CFF tables loader service (specification). * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h index 8362cb8724d..748a8caf887 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svcid.h @@ -4,7 +4,7 @@ * * The FreeType CID font services (specification). * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h index 6b837e79fcd..690fdc2a24f 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h @@ -4,7 +4,7 @@ * * The FreeType font format service (specification only). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h index 6126ec9ada4..7128d6f3d7a 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgldict.h @@ -4,7 +4,7 @@ * * The FreeType glyph dictionary services (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h index 29cf5528189..1ca3e0a031b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svgxval.h @@ -4,7 +4,7 @@ * * FreeType API for validating TrueTypeGX/AAT tables (specification). * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h index ac1bc30c412..8a3d59bec6d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svkern.h @@ -4,7 +4,7 @@ * * The FreeType Kerning service (specification). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h index 8b3563b25ca..4dde3a8151a 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmetric.h @@ -4,7 +4,7 @@ * * The FreeType services for metrics variations (specification). * - * Copyright (C) 2016-2024 by + * Copyright (C) 2016-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -77,7 +77,7 @@ FT_BEGIN_HEADER typedef void (*FT_Metrics_Adjust_Func)( FT_Face face ); - typedef FT_Error + typedef void (*FT_Size_Reset_Func)( FT_Size size ); diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h index 5288fadf375..9be133e2db0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svmm.h @@ -4,7 +4,7 @@ * * The FreeType Multiple Masters and GX var services (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h index 7aea7ec11f0..933e5de98da 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svotval.h @@ -4,7 +4,7 @@ * * The FreeType OpenType validation service (specification). * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h index b2fac6d086b..c81b6a68a8b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpfr.h @@ -4,7 +4,7 @@ * * Internal PFR service functions (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h index d19f3adc6d5..33864ebc344 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpostnm.h @@ -4,7 +4,7 @@ * * The FreeType PostScript name services (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h index ba39c0dd4da..0eb79c885d8 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svprop.h @@ -4,7 +4,7 @@ * * The FreeType property service (specification). * - * Copyright (C) 2012-2024 by + * Copyright (C) 2012-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h index d4908ee41aa..8f85d12157c 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpscmap.h @@ -4,7 +4,7 @@ * * The FreeType PostScript charmap service (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h index 2aadcdd02a1..83de04478df 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svpsinfo.h @@ -4,7 +4,7 @@ * * The FreeType PostScript info service (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h index 9e0f4ff202e..9bf5e3473c4 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svsfnt.h @@ -4,7 +4,7 @@ * * The FreeType SFNT table loading service (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h index 250886bcc5d..fc9b0aeb8e3 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h @@ -4,7 +4,7 @@ * * The FreeType TrueType/sfnt cmap extra information service. * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * Masatake YAMATO, Redhat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h index 14967529a9a..979e9ea102e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svtteng.h @@ -4,7 +4,7 @@ * * The FreeType TrueType engine query service (specification). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h index f190b3985d0..e4f54c10037 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttglyf.h @@ -4,7 +4,7 @@ * * The FreeType TrueType glyph service. * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h index 49f3fb7f775..ff887ffdc03 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svwinfnt.h @@ -4,7 +4,7 @@ * * The FreeType Windows FNT/FONT service (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h index 35e4e73af02..adba2178877 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/sfnt.h @@ -4,7 +4,7 @@ * * High-level 'sfnt' driver interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -612,7 +612,7 @@ FT_BEGIN_HEADER * * @return: * Value~1 if a ClipBox is found. If no clip box is found or an - * error occured, value~0 is returned. + * error occurred, value~0 is returned. */ typedef FT_Bool ( *TT_Get_Color_Glyph_ClipBox_Func )( TT_Face face, @@ -707,7 +707,7 @@ FT_BEGIN_HEADER * * @return: * Value~1 if everything is OK. Value~0 if no details can be found for - * this paint or any other error occured. + * this paint or any other error occurred. */ typedef FT_Bool ( *TT_Get_Paint_Func )( TT_Face face, @@ -808,7 +808,7 @@ FT_BEGIN_HEADER * corresponding (1,0) Apple entry. * * @return: - * 1 if there is either a win or apple entry (or both), 0 otheriwse. + * 1 if there is either a win or apple entry (or both), 0 otherwise. */ typedef FT_Bool (*TT_Get_Name_ID_Func)( TT_Face face, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h index 68c99efb10a..20c73b2fbd2 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/svginterface.h @@ -4,7 +4,7 @@ * * Interface of ot-svg module (specification only). * - * Copyright (C) 2022-2024 by + * Copyright (C) 2022-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h index 1821ae5cc83..5b26e4620d0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/t1types.h @@ -5,7 +5,7 @@ * Basic Type1/Type2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h index 7053e656a7e..d0e5eee89bc 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h @@ -5,7 +5,7 @@ * Basic SFNT/TrueType type definitions and interface (specification * only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -930,8 +930,8 @@ FT_BEGIN_HEADER * resolution and scaling independent parts of a TrueType font resource. * * @note: - * The TT_Face structure is also used as a 'parent class' for the - * OpenType-CFF class (T2_Face). + * The TT_Face structure is also used for CFF support; see file + * `cffotypes.h`. */ typedef struct TT_FaceRec_* TT_Face; @@ -1276,10 +1276,6 @@ FT_BEGIN_HEADER * * If varied by the `CVAR' table, non-integer values are possible. * - * interpreter :: - * A pointer to the TrueType bytecode interpreters field is also used - * to hook the debugger in 'ttdebug'. - * * extra :: * Reserved for third-party font drivers. * @@ -1521,10 +1517,6 @@ FT_BEGIN_HEADER FT_ULong cvt_size; FT_Int32* cvt; - /* A pointer to the bytecode interpreter to use. This is also */ - /* used to hook the debugger for the `ttdebug' utility. */ - TT_Interpreter interpreter; - /************************************************************************ * @@ -1582,11 +1574,6 @@ FT_BEGIN_HEADER FT_UInt32 kern_avail_bits; FT_UInt32 kern_order_bits; -#ifdef TT_CONFIG_OPTION_GPOS_KERNING - FT_Byte* gpos_table; - FT_Bool gpos_kerning_available; -#endif - #ifdef TT_CONFIG_OPTION_BDF TT_BDFRec bdf; #endif /* TT_CONFIG_OPTION_BDF */ @@ -1608,6 +1595,15 @@ FT_BEGIN_HEADER /* since 2.12 */ void* svg; +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + /* since 2.13.3 */ + FT_Byte* gpos_table; + /* since 2.14 */ + /* This is actually an array of GPOS lookup subtables. */ + FT_UInt32* gpos_lookups_kerning; + FT_UInt num_gpos_lookups_kerning; +#endif + } TT_FaceRec; @@ -1621,15 +1617,6 @@ FT_BEGIN_HEADER * coordinates. * * @fields: - * memory :: - * A handle to the memory manager. - * - * max_points :: - * The maximum size in points of the zone. - * - * max_contours :: - * Max size in links contours of the zone. - * * n_points :: * The current number of points in the zone. * @@ -1653,9 +1640,6 @@ FT_BEGIN_HEADER */ typedef struct TT_GlyphZoneRec_ { - FT_Memory memory; - FT_UShort max_points; - FT_UShort max_contours; FT_UShort n_points; /* number of points in zone */ FT_UShort n_contours; /* number of contours */ @@ -1714,7 +1698,6 @@ FT_BEGIN_HEADER TT_GlyphZoneRec zone; TT_ExecContext exec; - FT_Byte* instructions; FT_ULong ins_pos; /* for possible extensibility in other formats */ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h index 4a169d12f57..7d5b7df0fa1 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/wofftypes.h @@ -5,7 +5,7 @@ * Basic WOFF/WOFF2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h b/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h index 9d356938cc7..326bbcd0153 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/otsvg.h @@ -4,7 +4,7 @@ * * Interface for OT-SVG support related things (specification). * - * Copyright (C) 2022-2024 by + * Copyright (C) 2022-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h b/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h index fbd558aa34d..fc3c1706de5 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/t1tables.h @@ -5,7 +5,7 @@ * Basic Type 1/Type 2 tables definitions and interface (specification * only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h b/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h index d5d470e380f..3ef61091cc9 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ttnameid.h @@ -4,7 +4,7 @@ * * TrueType name ID definitions (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -436,7 +436,7 @@ FT_BEGIN_HEADER * * The canonical source for Microsoft's IDs is * - * https://docs.microsoft.com/en-us/windows/desktop/Intl/language-identifier-constants-and-strings , + * https://learn.microsoft.com/windows/win32/intl/language-identifier-constants-and-strings , * * however, we only provide macros for language identifiers present in * the OpenType specification: Microsoft has abandoned the concept of @@ -847,113 +847,113 @@ FT_BEGIN_HEADER /* --------------- */ /* Bit 0 Basic Latin */ -#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ +#define TT_UCR_BASIC_LATIN (1UL << 0) /* U+0020-U+007E */ /* Bit 1 C1 Controls and Latin-1 Supplement */ -#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */ +#define TT_UCR_LATIN1_SUPPLEMENT (1UL << 1) /* U+0080-U+00FF */ /* Bit 2 Latin Extended-A */ -#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ +#define TT_UCR_LATIN_EXTENDED_A (1UL << 2) /* U+0100-U+017F */ /* Bit 3 Latin Extended-B */ -#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ +#define TT_UCR_LATIN_EXTENDED_B (1UL << 3) /* U+0180-U+024F */ /* Bit 4 IPA Extensions */ /* Phonetic Extensions */ /* Phonetic Extensions Supplement */ -#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ +#define TT_UCR_IPA_EXTENSIONS (1UL << 4) /* U+0250-U+02AF */ /* U+1D00-U+1D7F */ /* U+1D80-U+1DBF */ /* Bit 5 Spacing Modifier Letters */ /* Modifier Tone Letters */ -#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ +#define TT_UCR_SPACING_MODIFIER (1UL << 5) /* U+02B0-U+02FF */ /* U+A700-U+A71F */ /* Bit 6 Combining Diacritical Marks */ /* Combining Diacritical Marks Supplement */ -#define TT_UCR_COMBINING_DIACRITICAL_MARKS (1L << 6) /* U+0300-U+036F */ +#define TT_UCR_COMBINING_DIACRITICAL_MARKS (1UL << 6) /* U+0300-U+036F */ /* U+1DC0-U+1DFF */ /* Bit 7 Greek and Coptic */ -#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ +#define TT_UCR_GREEK (1UL << 7) /* U+0370-U+03FF */ /* Bit 8 Coptic */ -#define TT_UCR_COPTIC (1L << 8) /* U+2C80-U+2CFF */ +#define TT_UCR_COPTIC (1UL << 8) /* U+2C80-U+2CFF */ /* Bit 9 Cyrillic */ /* Cyrillic Supplement */ /* Cyrillic Extended-A */ /* Cyrillic Extended-B */ -#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ +#define TT_UCR_CYRILLIC (1UL << 9) /* U+0400-U+04FF */ /* U+0500-U+052F */ /* U+2DE0-U+2DFF */ /* U+A640-U+A69F */ /* Bit 10 Armenian */ -#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ +#define TT_UCR_ARMENIAN (1UL << 10) /* U+0530-U+058F */ /* Bit 11 Hebrew */ -#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ +#define TT_UCR_HEBREW (1UL << 11) /* U+0590-U+05FF */ /* Bit 12 Vai */ -#define TT_UCR_VAI (1L << 12) /* U+A500-U+A63F */ +#define TT_UCR_VAI (1UL << 12) /* U+A500-U+A63F */ /* Bit 13 Arabic */ /* Arabic Supplement */ -#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ +#define TT_UCR_ARABIC (1UL << 13) /* U+0600-U+06FF */ /* U+0750-U+077F */ /* Bit 14 NKo */ -#define TT_UCR_NKO (1L << 14) /* U+07C0-U+07FF */ +#define TT_UCR_NKO (1UL << 14) /* U+07C0-U+07FF */ /* Bit 15 Devanagari */ -#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */ - /* Bit 16 Bengali */ -#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */ +#define TT_UCR_DEVANAGARI (1UL << 15) /* U+0900-U+097F */ + /* Bit 16 Bangla (Bengali) */ +#define TT_UCR_BENGALI (1UL << 16) /* U+0980-U+09FF */ /* Bit 17 Gurmukhi */ -#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ +#define TT_UCR_GURMUKHI (1UL << 17) /* U+0A00-U+0A7F */ /* Bit 18 Gujarati */ -#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */ - /* Bit 19 Oriya */ -#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */ +#define TT_UCR_GUJARATI (1UL << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya (Odia) */ +#define TT_UCR_ORIYA (1UL << 19) /* U+0B00-U+0B7F */ /* Bit 20 Tamil */ -#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ +#define TT_UCR_TAMIL (1UL << 20) /* U+0B80-U+0BFF */ /* Bit 21 Telugu */ -#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ +#define TT_UCR_TELUGU (1UL << 21) /* U+0C00-U+0C7F */ /* Bit 22 Kannada */ -#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ +#define TT_UCR_KANNADA (1UL << 22) /* U+0C80-U+0CFF */ /* Bit 23 Malayalam */ -#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ +#define TT_UCR_MALAYALAM (1UL << 23) /* U+0D00-U+0D7F */ /* Bit 24 Thai */ -#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ +#define TT_UCR_THAI (1UL << 24) /* U+0E00-U+0E7F */ /* Bit 25 Lao */ -#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ +#define TT_UCR_LAO (1UL << 25) /* U+0E80-U+0EFF */ /* Bit 26 Georgian */ /* Georgian Supplement */ -#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ +#define TT_UCR_GEORGIAN (1UL << 26) /* U+10A0-U+10FF */ /* U+2D00-U+2D2F */ /* Bit 27 Balinese */ -#define TT_UCR_BALINESE (1L << 27) /* U+1B00-U+1B7F */ +#define TT_UCR_BALINESE (1UL << 27) /* U+1B00-U+1B7F */ /* Bit 28 Hangul Jamo */ -#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ +#define TT_UCR_HANGUL_JAMO (1UL << 28) /* U+1100-U+11FF */ /* Bit 29 Latin Extended Additional */ /* Latin Extended-C */ /* Latin Extended-D */ -#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1UL << 29) /* U+1E00-U+1EFF */ /* U+2C60-U+2C7F */ /* U+A720-U+A7FF */ /* Bit 30 Greek Extended */ -#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ +#define TT_UCR_GREEK_EXTENDED (1UL << 30) /* U+1F00-U+1FFF */ /* Bit 31 General Punctuation */ /* Supplemental Punctuation */ -#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ +#define TT_UCR_GENERAL_PUNCTUATION (1UL << 31) /* U+2000-U+206F */ /* U+2E00-U+2E7F */ /* ulUnicodeRange2 */ /* --------------- */ /* Bit 32 Superscripts And Subscripts */ -#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1UL << 0) /* U+2070-U+209F */ /* Bit 33 Currency Symbols */ -#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ +#define TT_UCR_CURRENCY_SYMBOLS (1UL << 1) /* U+20A0-U+20CF */ /* Bit 34 Combining Diacritical Marks For Symbols */ #define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ - (1L << 2) /* U+20D0-U+20FF */ + (1UL << 2) /* U+20D0-U+20FF */ /* Bit 35 Letterlike Symbols */ -#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1UL << 3) /* U+2100-U+214F */ /* Bit 36 Number Forms */ -#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ +#define TT_UCR_NUMBER_FORMS (1UL << 4) /* U+2150-U+218F */ /* Bit 37 Arrows */ /* Supplemental Arrows-A */ /* Supplemental Arrows-B */ /* Miscellaneous Symbols and Arrows */ -#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ +#define TT_UCR_ARROWS (1UL << 5) /* U+2190-U+21FF */ /* U+27F0-U+27FF */ /* U+2900-U+297F */ /* U+2B00-U+2BFF */ @@ -961,52 +961,52 @@ FT_BEGIN_HEADER /* Supplemental Mathematical Operators */ /* Miscellaneous Mathematical Symbols-A */ /* Miscellaneous Mathematical Symbols-B */ -#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1UL << 6) /* U+2200-U+22FF */ /* U+2A00-U+2AFF */ /* U+27C0-U+27EF */ /* U+2980-U+29FF */ /* Bit 39 Miscellaneous Technical */ -#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1UL << 7) /* U+2300-U+23FF */ /* Bit 40 Control Pictures */ -#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ +#define TT_UCR_CONTROL_PICTURES (1UL << 8) /* U+2400-U+243F */ /* Bit 41 Optical Character Recognition */ -#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ +#define TT_UCR_OCR (1UL << 9) /* U+2440-U+245F */ /* Bit 42 Enclosed Alphanumerics */ -#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1UL << 10) /* U+2460-U+24FF */ /* Bit 43 Box Drawing */ -#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ +#define TT_UCR_BOX_DRAWING (1UL << 11) /* U+2500-U+257F */ /* Bit 44 Block Elements */ -#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ +#define TT_UCR_BLOCK_ELEMENTS (1UL << 12) /* U+2580-U+259F */ /* Bit 45 Geometric Shapes */ -#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ +#define TT_UCR_GEOMETRIC_SHAPES (1UL << 13) /* U+25A0-U+25FF */ /* Bit 46 Miscellaneous Symbols */ -#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1UL << 14) /* U+2600-U+26FF */ /* Bit 47 Dingbats */ -#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ +#define TT_UCR_DINGBATS (1UL << 15) /* U+2700-U+27BF */ /* Bit 48 CJK Symbols and Punctuation */ -#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ +#define TT_UCR_CJK_SYMBOLS (1UL << 16) /* U+3000-U+303F */ /* Bit 49 Hiragana */ -#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ +#define TT_UCR_HIRAGANA (1UL << 17) /* U+3040-U+309F */ /* Bit 50 Katakana */ /* Katakana Phonetic Extensions */ -#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ +#define TT_UCR_KATAKANA (1UL << 18) /* U+30A0-U+30FF */ /* U+31F0-U+31FF */ /* Bit 51 Bopomofo */ /* Bopomofo Extended */ -#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ +#define TT_UCR_BOPOMOFO (1UL << 19) /* U+3100-U+312F */ /* U+31A0-U+31BF */ /* Bit 52 Hangul Compatibility Jamo */ -#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1UL << 20) /* U+3130-U+318F */ /* Bit 53 Phags-Pa */ -#define TT_UCR_CJK_MISC (1L << 21) /* U+A840-U+A87F */ -#define TT_UCR_KANBUN TT_UCR_CJK_MISC /* deprecated */ -#define TT_UCR_PHAGSPA +#define TT_UCR_PHAGSPA (1UL << 21) /* U+A840-U+A87F */ +#define TT_UCR_KANBUN TT_UCR_PHAGSPA /* deprecated */ +#define TT_UCR_CJK_MISC TT_UCR_PHAGSPA /* deprecated */ /* Bit 54 Enclosed CJK Letters and Months */ -#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1UL << 22) /* U+3200-U+32FF */ /* Bit 55 CJK Compatibility */ -#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ +#define TT_UCR_CJK_COMPATIBILITY (1UL << 23) /* U+3300-U+33FF */ /* Bit 56 Hangul Syllables */ -#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ +#define TT_UCR_HANGUL (1UL << 24) /* U+AC00-U+D7A3 */ /* Bit 57 High Surrogates */ /* High Private Use Surrogates */ /* Low Surrogates */ @@ -1017,12 +1017,12 @@ FT_BEGIN_HEADER /* Basic Multilingual Plane that is */ /* supported by this font. So it really */ /* means >= U+10000. */ -#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */ +#define TT_UCR_SURROGATES (1UL << 25) /* U+D800-U+DB7F */ /* U+DB80-U+DBFF */ /* U+DC00-U+DFFF */ #define TT_UCR_NON_PLANE_0 TT_UCR_SURROGATES /* Bit 58 Phoenician */ -#define TT_UCR_PHOENICIAN (1L << 26) /*U+10900-U+1091F*/ +#define TT_UCR_PHOENICIAN (1UL << 26) /*U+10900-U+1091F*/ /* Bit 59 CJK Unified Ideographs */ /* CJK Radicals Supplement */ /* Kangxi Radicals */ @@ -1030,7 +1030,7 @@ FT_BEGIN_HEADER /* CJK Unified Ideographs Extension A */ /* CJK Unified Ideographs Extension B */ /* Kanbun */ -#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1UL << 27) /* U+4E00-U+9FFF */ /* U+2E80-U+2EFF */ /* U+2F00-U+2FDF */ /* U+2FF0-U+2FFF */ @@ -1038,178 +1038,178 @@ FT_BEGIN_HEADER /*U+20000-U+2A6DF*/ /* U+3190-U+319F */ /* Bit 60 Private Use */ -#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ +#define TT_UCR_PRIVATE_USE (1UL << 28) /* U+E000-U+F8FF */ /* Bit 61 CJK Strokes */ /* CJK Compatibility Ideographs */ /* CJK Compatibility Ideographs Supplement */ -#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+31C0-U+31EF */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1UL << 29) /* U+31C0-U+31EF */ /* U+F900-U+FAFF */ /*U+2F800-U+2FA1F*/ /* Bit 62 Alphabetic Presentation Forms */ -#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1UL << 30) /* U+FB00-U+FB4F */ /* Bit 63 Arabic Presentation Forms-A */ -#define TT_UCR_ARABIC_PRESENTATION_FORMS_A (1L << 31) /* U+FB50-U+FDFF */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A (1UL << 31) /* U+FB50-U+FDFF */ /* ulUnicodeRange3 */ /* --------------- */ /* Bit 64 Combining Half Marks */ -#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ +#define TT_UCR_COMBINING_HALF_MARKS (1UL << 0) /* U+FE20-U+FE2F */ /* Bit 65 Vertical forms */ /* CJK Compatibility Forms */ -#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE10-U+FE1F */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1UL << 1) /* U+FE10-U+FE1F */ /* U+FE30-U+FE4F */ /* Bit 66 Small Form Variants */ -#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ +#define TT_UCR_SMALL_FORM_VARIANTS (1UL << 2) /* U+FE50-U+FE6F */ /* Bit 67 Arabic Presentation Forms-B */ -#define TT_UCR_ARABIC_PRESENTATION_FORMS_B (1L << 3) /* U+FE70-U+FEFE */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B (1UL << 3) /* U+FE70-U+FEFF */ /* Bit 68 Halfwidth and Fullwidth Forms */ -#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1UL << 4) /* U+FF00-U+FFEF */ /* Bit 69 Specials */ -#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ +#define TT_UCR_SPECIALS (1UL << 5) /* U+FFF0-U+FFFF */ /* Bit 70 Tibetan */ -#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */ +#define TT_UCR_TIBETAN (1UL << 6) /* U+0F00-U+0FFF */ /* Bit 71 Syriac */ -#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ +#define TT_UCR_SYRIAC (1UL << 7) /* U+0700-U+074F */ /* Bit 72 Thaana */ -#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ +#define TT_UCR_THAANA (1UL << 8) /* U+0780-U+07BF */ /* Bit 73 Sinhala */ -#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ +#define TT_UCR_SINHALA (1UL << 9) /* U+0D80-U+0DFF */ /* Bit 74 Myanmar */ -#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ +#define TT_UCR_MYANMAR (1UL << 10) /* U+1000-U+109F */ /* Bit 75 Ethiopic */ /* Ethiopic Supplement */ /* Ethiopic Extended */ -#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */ +#define TT_UCR_ETHIOPIC (1UL << 11) /* U+1200-U+137F */ /* U+1380-U+139F */ /* U+2D80-U+2DDF */ /* Bit 76 Cherokee */ -#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ +#define TT_UCR_CHEROKEE (1UL << 12) /* U+13A0-U+13FF */ /* Bit 77 Unified Canadian Aboriginal Syllabics */ -#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1UL << 13) /* U+1400-U+167F */ /* Bit 78 Ogham */ -#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ +#define TT_UCR_OGHAM (1UL << 14) /* U+1680-U+169F */ /* Bit 79 Runic */ -#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ +#define TT_UCR_RUNIC (1UL << 15) /* U+16A0-U+16FF */ /* Bit 80 Khmer */ /* Khmer Symbols */ -#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ +#define TT_UCR_KHMER (1UL << 16) /* U+1780-U+17FF */ /* U+19E0-U+19FF */ /* Bit 81 Mongolian */ -#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ +#define TT_UCR_MONGOLIAN (1UL << 17) /* U+1800-U+18AF */ /* Bit 82 Braille Patterns */ -#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ +#define TT_UCR_BRAILLE (1UL << 18) /* U+2800-U+28FF */ /* Bit 83 Yi Syllables */ /* Yi Radicals */ -#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */ +#define TT_UCR_YI (1UL << 19) /* U+A000-U+A48F */ /* U+A490-U+A4CF */ /* Bit 84 Tagalog */ /* Hanunoo */ /* Buhid */ /* Tagbanwa */ -#define TT_UCR_PHILIPPINE (1L << 20) /* U+1700-U+171F */ +#define TT_UCR_PHILIPPINE (1UL << 20) /* U+1700-U+171F */ /* U+1720-U+173F */ /* U+1740-U+175F */ /* U+1760-U+177F */ /* Bit 85 Old Italic */ -#define TT_UCR_OLD_ITALIC (1L << 21) /*U+10300-U+1032F*/ +#define TT_UCR_OLD_ITALIC (1UL << 21) /*U+10300-U+1032F*/ /* Bit 86 Gothic */ -#define TT_UCR_GOTHIC (1L << 22) /*U+10330-U+1034F*/ +#define TT_UCR_GOTHIC (1UL << 22) /*U+10330-U+1034F*/ /* Bit 87 Deseret */ -#define TT_UCR_DESERET (1L << 23) /*U+10400-U+1044F*/ +#define TT_UCR_DESERET (1UL << 23) /*U+10400-U+1044F*/ /* Bit 88 Byzantine Musical Symbols */ /* Musical Symbols */ /* Ancient Greek Musical Notation */ -#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) /*U+1D000-U+1D0FF*/ +#define TT_UCR_MUSICAL_SYMBOLS (1UL << 24) /*U+1D000-U+1D0FF*/ /*U+1D100-U+1D1FF*/ /*U+1D200-U+1D24F*/ /* Bit 89 Mathematical Alphanumeric Symbols */ -#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) /*U+1D400-U+1D7FF*/ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1UL << 25) /*U+1D400-U+1D7FF*/ /* Bit 90 Private Use (plane 15) */ /* Private Use (plane 16) */ -#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1L << 26) /*U+F0000-U+FFFFD*/ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1UL << 26) /*U+F0000-U+FFFFD*/ /*U+100000-U+10FFFD*/ /* Bit 91 Variation Selectors */ /* Variation Selectors Supplement */ -#define TT_UCR_VARIATION_SELECTORS (1L << 27) /* U+FE00-U+FE0F */ +#define TT_UCR_VARIATION_SELECTORS (1UL << 27) /* U+FE00-U+FE0F */ /*U+E0100-U+E01EF*/ /* Bit 92 Tags */ -#define TT_UCR_TAGS (1L << 28) /*U+E0000-U+E007F*/ +#define TT_UCR_TAGS (1UL << 28) /*U+E0000-U+E007F*/ /* Bit 93 Limbu */ -#define TT_UCR_LIMBU (1L << 29) /* U+1900-U+194F */ +#define TT_UCR_LIMBU (1UL << 29) /* U+1900-U+194F */ /* Bit 94 Tai Le */ -#define TT_UCR_TAI_LE (1L << 30) /* U+1950-U+197F */ +#define TT_UCR_TAI_LE (1UL << 30) /* U+1950-U+197F */ /* Bit 95 New Tai Lue */ -#define TT_UCR_NEW_TAI_LUE (1L << 31) /* U+1980-U+19DF */ +#define TT_UCR_NEW_TAI_LUE (1UL << 31) /* U+1980-U+19DF */ /* ulUnicodeRange4 */ /* --------------- */ /* Bit 96 Buginese */ -#define TT_UCR_BUGINESE (1L << 0) /* U+1A00-U+1A1F */ +#define TT_UCR_BUGINESE (1UL << 0) /* U+1A00-U+1A1F */ /* Bit 97 Glagolitic */ -#define TT_UCR_GLAGOLITIC (1L << 1) /* U+2C00-U+2C5F */ +#define TT_UCR_GLAGOLITIC (1UL << 1) /* U+2C00-U+2C5F */ /* Bit 98 Tifinagh */ -#define TT_UCR_TIFINAGH (1L << 2) /* U+2D30-U+2D7F */ +#define TT_UCR_TIFINAGH (1UL << 2) /* U+2D30-U+2D7F */ /* Bit 99 Yijing Hexagram Symbols */ -#define TT_UCR_YIJING (1L << 3) /* U+4DC0-U+4DFF */ +#define TT_UCR_YIJING (1UL << 3) /* U+4DC0-U+4DFF */ /* Bit 100 Syloti Nagri */ -#define TT_UCR_SYLOTI_NAGRI (1L << 4) /* U+A800-U+A82F */ +#define TT_UCR_SYLOTI_NAGRI (1UL << 4) /* U+A800-U+A82F */ /* Bit 101 Linear B Syllabary */ /* Linear B Ideograms */ /* Aegean Numbers */ -#define TT_UCR_LINEAR_B (1L << 5) /*U+10000-U+1007F*/ +#define TT_UCR_LINEAR_B (1UL << 5) /*U+10000-U+1007F*/ /*U+10080-U+100FF*/ /*U+10100-U+1013F*/ /* Bit 102 Ancient Greek Numbers */ -#define TT_UCR_ANCIENT_GREEK_NUMBERS (1L << 6) /*U+10140-U+1018F*/ +#define TT_UCR_ANCIENT_GREEK_NUMBERS (1UL << 6) /*U+10140-U+1018F*/ /* Bit 103 Ugaritic */ -#define TT_UCR_UGARITIC (1L << 7) /*U+10380-U+1039F*/ +#define TT_UCR_UGARITIC (1UL << 7) /*U+10380-U+1039F*/ /* Bit 104 Old Persian */ -#define TT_UCR_OLD_PERSIAN (1L << 8) /*U+103A0-U+103DF*/ +#define TT_UCR_OLD_PERSIAN (1UL << 8) /*U+103A0-U+103DF*/ /* Bit 105 Shavian */ -#define TT_UCR_SHAVIAN (1L << 9) /*U+10450-U+1047F*/ +#define TT_UCR_SHAVIAN (1UL << 9) /*U+10450-U+1047F*/ /* Bit 106 Osmanya */ -#define TT_UCR_OSMANYA (1L << 10) /*U+10480-U+104AF*/ +#define TT_UCR_OSMANYA (1UL << 10) /*U+10480-U+104AF*/ /* Bit 107 Cypriot Syllabary */ -#define TT_UCR_CYPRIOT_SYLLABARY (1L << 11) /*U+10800-U+1083F*/ +#define TT_UCR_CYPRIOT_SYLLABARY (1UL << 11) /*U+10800-U+1083F*/ /* Bit 108 Kharoshthi */ -#define TT_UCR_KHAROSHTHI (1L << 12) /*U+10A00-U+10A5F*/ +#define TT_UCR_KHAROSHTHI (1UL << 12) /*U+10A00-U+10A5F*/ /* Bit 109 Tai Xuan Jing Symbols */ -#define TT_UCR_TAI_XUAN_JING (1L << 13) /*U+1D300-U+1D35F*/ +#define TT_UCR_TAI_XUAN_JING (1UL << 13) /*U+1D300-U+1D35F*/ /* Bit 110 Cuneiform */ /* Cuneiform Numbers and Punctuation */ -#define TT_UCR_CUNEIFORM (1L << 14) /*U+12000-U+123FF*/ +#define TT_UCR_CUNEIFORM (1UL << 14) /*U+12000-U+123FF*/ /*U+12400-U+1247F*/ /* Bit 111 Counting Rod Numerals */ -#define TT_UCR_COUNTING_ROD_NUMERALS (1L << 15) /*U+1D360-U+1D37F*/ +#define TT_UCR_COUNTING_ROD_NUMERALS (1UL << 15) /*U+1D360-U+1D37F*/ /* Bit 112 Sundanese */ -#define TT_UCR_SUNDANESE (1L << 16) /* U+1B80-U+1BBF */ +#define TT_UCR_SUNDANESE (1UL << 16) /* U+1B80-U+1BBF */ /* Bit 113 Lepcha */ -#define TT_UCR_LEPCHA (1L << 17) /* U+1C00-U+1C4F */ +#define TT_UCR_LEPCHA (1UL << 17) /* U+1C00-U+1C4F */ /* Bit 114 Ol Chiki */ -#define TT_UCR_OL_CHIKI (1L << 18) /* U+1C50-U+1C7F */ +#define TT_UCR_OL_CHIKI (1UL << 18) /* U+1C50-U+1C7F */ /* Bit 115 Saurashtra */ -#define TT_UCR_SAURASHTRA (1L << 19) /* U+A880-U+A8DF */ +#define TT_UCR_SAURASHTRA (1UL << 19) /* U+A880-U+A8DF */ /* Bit 116 Kayah Li */ -#define TT_UCR_KAYAH_LI (1L << 20) /* U+A900-U+A92F */ +#define TT_UCR_KAYAH_LI (1UL << 20) /* U+A900-U+A92F */ /* Bit 117 Rejang */ -#define TT_UCR_REJANG (1L << 21) /* U+A930-U+A95F */ +#define TT_UCR_REJANG (1UL << 21) /* U+A930-U+A95F */ /* Bit 118 Cham */ -#define TT_UCR_CHAM (1L << 22) /* U+AA00-U+AA5F */ +#define TT_UCR_CHAM (1UL << 22) /* U+AA00-U+AA5F */ /* Bit 119 Ancient Symbols */ -#define TT_UCR_ANCIENT_SYMBOLS (1L << 23) /*U+10190-U+101CF*/ +#define TT_UCR_ANCIENT_SYMBOLS (1UL << 23) /*U+10190-U+101CF*/ /* Bit 120 Phaistos Disc */ -#define TT_UCR_PHAISTOS_DISC (1L << 24) /*U+101D0-U+101FF*/ +#define TT_UCR_PHAISTOS_DISC (1UL << 24) /*U+101D0-U+101FF*/ /* Bit 121 Carian */ /* Lycian */ /* Lydian */ -#define TT_UCR_OLD_ANATOLIAN (1L << 25) /*U+102A0-U+102DF*/ +#define TT_UCR_OLD_ANATOLIAN (1UL << 25) /*U+102A0-U+102DF*/ /*U+10280-U+1029F*/ /*U+10920-U+1093F*/ /* Bit 122 Domino Tiles */ /* Mahjong Tiles */ -#define TT_UCR_GAME_TILES (1L << 26) /*U+1F030-U+1F09F*/ +#define TT_UCR_GAME_TILES (1UL << 26) /*U+1F030-U+1F09F*/ /*U+1F000-U+1F02F*/ /* Bit 123-127 Reserved for process-internal usage */ diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h b/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h index 2cf0ff1bc61..aa4336435d9 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/tttables.h @@ -5,7 +5,7 @@ * Basic SFNT/TrueType tables definitions and interface * (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -192,7 +192,7 @@ FT_BEGIN_HEADER * A pointer into the 'hmtx' table. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `caret_Slope_Rise`, * `caret_Slope_Run`, and `caret_Offset`. @@ -310,7 +310,7 @@ FT_BEGIN_HEADER * A pointer into the 'vmtx' table. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `Ascender`, `Descender`, * `Line_Gap`, `caret_Slope_Rise`, `caret_Slope_Run`, and `caret_Offset`. @@ -359,7 +359,7 @@ FT_BEGIN_HEADER * table. In this case, the `version` field is always set to 0xFFFF. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `sCapHeight`, `sTypoAscender`, * `sTypoDescender`, `sTypoLineGap`, `sxHeight`, `usWinAscent`, @@ -442,7 +442,7 @@ FT_BEGIN_HEADER * them. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `underlinePosition` and * `underlineThickness`. @@ -705,6 +705,9 @@ FT_BEGIN_HEADER * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new * one with @FT_MAKE_TAG. * + * [Since 2.14] Use value~1 if you want to access the table directory + * of the (currently selected) font. + * * offset :: * The starting offset in the table (or file if tag~==~0). * diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h index da0af5d3f23..56bb0a3ee5e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h @@ -4,7 +4,7 @@ * * Tags for TrueType and OpenType tables (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/include/ft2build.h b/src/java.desktop/share/native/libfreetype/include/ft2build.h index d3d7685039c..3008aea7cf5 100644 --- a/src/java.desktop/share/native/libfreetype/include/ft2build.h +++ b/src/java.desktop/share/native/libfreetype/include/ft2build.h @@ -4,7 +4,7 @@ * * FreeType 2 build and setup macros. * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.c b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.c new file mode 100644 index 00000000000..6637cacfccf --- /dev/null +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.c @@ -0,0 +1,1612 @@ +/**************************************************************************** + * + * afadjust.c + * + * Auto-fitter routines to adjust components based on charcode (body). + * + * Copyright (C) 2023-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Craig White . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#include "afadjust.h" +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ +# include "afgsub.h" +#endif + +#include +#include +#include +#include + +#define AF_ADJUSTMENT_DATABASE_LENGTH \ + ( sizeof ( adjustment_database ) / \ + sizeof ( adjustment_database[0] ) ) + +#undef FT_COMPONENT +#define FT_COMPONENT afadjust + + + typedef struct AF_AdjustmentDatabaseEntry_ + { + FT_UInt32 codepoint; + FT_UInt32 flags; + + } AF_AdjustmentDatabaseEntry; + + + /* + All entries in this list must be sorted by ascending Unicode code + points. The table entries are 3 numbers consisting of: + + - Unicode code point. + - The vertical adjustment type. This should be a combination of the + AF_ADJUST_XXX and AF_IGNORE_XXX macros. + */ + static AF_AdjustmentDatabaseEntry adjustment_database[] = + { + /* C0 Controls and Basic Latin */ + { 0x21, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ! */ + { 0x51, AF_IGNORE_CAPITAL_BOTTOM } , /* Q */ + { 0x3F, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ? */ + { 0x69, AF_ADJUST_UP }, /* i */ + { 0x6A, AF_ADJUST_UP }, /* j */ +#if 0 + /* XXX TODO */ + { 0x7E, AF_ADJUST_TILDE_TOP }, /* ~ */ +#endif + + /* C1 Controls and Latin-1 Supplement */ + { 0xA1, AF_ADJUST_UP }, /* ¡ */ + { 0xA6, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ¦ */ + { 0xAA, AF_ADJUST_UP }, /* ª */ + { 0xBA, AF_ADJUST_UP }, /* º */ + { 0xBF, AF_ADJUST_UP }, /* ¿ */ + + { 0xC0, AF_ADJUST_UP }, /* À */ + { 0xC1, AF_ADJUST_UP }, /* Á */ + { 0xC2, AF_ADJUST_UP }, /* Â */ + { 0xC3, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ã */ + { 0xC4, AF_ADJUST_UP }, /* Ä */ + { 0xC5, AF_ADJUST_UP }, /* Å */ + { 0xC7, AF_IGNORE_CAPITAL_BOTTOM }, /* Ç */ + { 0xC8, AF_ADJUST_UP }, /* È */ + { 0xC9, AF_ADJUST_UP }, /* É */ + { 0xCA, AF_ADJUST_UP }, /* Ê */ + { 0xCB, AF_ADJUST_UP }, /* Ë */ + { 0xCC, AF_ADJUST_UP }, /* Ì */ + { 0xCD, AF_ADJUST_UP }, /* Í */ + { 0xCE, AF_ADJUST_UP }, /* Î */ + { 0xCF, AF_ADJUST_UP }, /* Ï */ + + { 0xD1, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ñ */ + { 0xD2, AF_ADJUST_UP }, /* Ò */ + { 0xD3, AF_ADJUST_UP }, /* Ó */ + { 0xD4, AF_ADJUST_UP }, /* Ô */ + { 0xD5, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Õ */ + { 0xD6, AF_ADJUST_UP }, /* Ö */ + { 0xD8, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ø */ + { 0xD9, AF_ADJUST_UP }, /* Ù */ + { 0xDA, AF_ADJUST_UP }, /* Ú */ + { 0xDB, AF_ADJUST_UP }, /* Û */ + { 0xDC, AF_ADJUST_UP }, /* Ü */ + { 0xDD, AF_ADJUST_UP }, /* Ý */ + + { 0xE0, AF_ADJUST_UP }, /* à */ + { 0xE1, AF_ADJUST_UP }, /* á */ + { 0xE2, AF_ADJUST_UP }, /* â */ + { 0xE3, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ã */ + { 0xE4, AF_ADJUST_UP }, /* ä */ + { 0xE5, AF_ADJUST_UP }, /* å */ + { 0xE7, AF_IGNORE_SMALL_BOTTOM }, /* ç */ + { 0xE8, AF_ADJUST_UP }, /* è */ + { 0xE9, AF_ADJUST_UP }, /* é */ + { 0xEA, AF_ADJUST_UP }, /* ê */ + { 0xEB, AF_ADJUST_UP }, /* ë */ + { 0xEC, AF_ADJUST_UP }, /* ì */ + { 0xED, AF_ADJUST_UP }, /* í */ + { 0xEE, AF_ADJUST_UP }, /* î */ + { 0xEF, AF_ADJUST_UP }, /* ï */ + + { 0xF1, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ñ */ + { 0xF2, AF_ADJUST_UP }, /* ò */ + { 0xF3, AF_ADJUST_UP }, /* ó */ + { 0xF4, AF_ADJUST_UP }, /* ô */ + { 0xF5, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* õ */ + { 0xF6, AF_ADJUST_UP }, /* ö */ + { 0xF8, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ø */ + { 0xF9, AF_ADJUST_UP }, /* ù */ + { 0xFA, AF_ADJUST_UP }, /* ú */ + { 0xFB, AF_ADJUST_UP }, /* û */ + { 0xFC, AF_ADJUST_UP }, /* ü */ + { 0xFD, AF_ADJUST_UP }, /* ý */ + { 0xFF, AF_ADJUST_UP }, /* ÿ */ + + /* Latin Extended-A */ + { 0x100, AF_ADJUST_UP }, /* Ā */ + { 0x101, AF_ADJUST_UP }, /* ā */ + { 0x102, AF_ADJUST_UP }, /* Ă */ + { 0x103, AF_ADJUST_UP }, /* ă */ + { 0x104, AF_IGNORE_CAPITAL_BOTTOM }, /* Ą */ + { 0x105, AF_IGNORE_SMALL_BOTTOM }, /* ą */ + { 0x106, AF_ADJUST_UP }, /* Ć */ + { 0x107, AF_ADJUST_UP }, /* ć */ + { 0x108, AF_ADJUST_UP }, /* Ĉ */ + { 0x109, AF_ADJUST_UP }, /* ĉ */ + { 0x10A, AF_ADJUST_UP }, /* Ċ */ + { 0x10B, AF_ADJUST_UP }, /* ċ */ + { 0x10C, AF_ADJUST_UP }, /* Č */ + { 0x10D, AF_ADJUST_UP }, /* č */ + { 0x10E, AF_ADJUST_UP }, /* Ď */ + + { 0x112, AF_ADJUST_UP }, /* Ē */ + { 0x113, AF_ADJUST_UP }, /* ē */ + { 0x114, AF_ADJUST_UP }, /* Ĕ */ + { 0x115, AF_ADJUST_UP }, /* ĕ */ + { 0x116, AF_ADJUST_UP }, /* Ė */ + { 0x117, AF_ADJUST_UP }, /* ė */ + { 0x118, AF_IGNORE_CAPITAL_BOTTOM }, /* Ę */ + { 0x119, AF_IGNORE_SMALL_BOTTOM }, /* ę */ + { 0x11A, AF_ADJUST_UP }, /* Ě */ + { 0x11B, AF_ADJUST_UP }, /* ě */ + { 0x11C, AF_ADJUST_UP }, /* Ĝ */ + { 0x11D, AF_ADJUST_UP }, /* ĝ */ + { 0x11E, AF_ADJUST_UP }, /* Ğ */ + { 0x11F, AF_ADJUST_UP }, /* ğ */ + + { 0x120, AF_ADJUST_UP }, /* Ġ */ + { 0x121, AF_ADJUST_UP }, /* ġ */ + { 0x122, AF_ADJUST_DOWN }, /* Ģ */ + { 0x123, AF_ADJUST_UP }, /* ģ */ + { 0x124, AF_ADJUST_UP }, /* Ĥ */ + { 0x125, AF_ADJUST_UP }, /* ĥ */ + { 0x128, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ĩ */ + { 0x129, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ĩ */ + { 0x12A, AF_ADJUST_UP }, /* Ī */ + { 0x12B, AF_ADJUST_UP }, /* ī */ + { 0x12C, AF_ADJUST_UP }, /* Ĭ */ + { 0x12D, AF_ADJUST_UP }, /* ĭ */ + { 0x12E, AF_IGNORE_CAPITAL_BOTTOM }, /* Į */ + { 0x12F, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* į */ + + { 0x130, AF_ADJUST_UP }, /* İ */ + { 0x133, AF_ADJUST_UP }, /* ij */ + { 0x134, AF_ADJUST_UP }, /* Ĵ */ + { 0x135, AF_ADJUST_UP }, /* ĵ */ + { 0x136, AF_ADJUST_DOWN }, /* Ķ */ + { 0x137, AF_ADJUST_DOWN }, /* ķ */ + { 0x139, AF_ADJUST_UP }, /* Ĺ */ + { 0x13A, AF_ADJUST_UP }, /* ĺ */ + { 0x13B, AF_ADJUST_DOWN }, /* Ļ */ + { 0x13C, AF_ADJUST_DOWN }, /* ļ */ + + { 0x143, AF_ADJUST_UP }, /* Ń */ + { 0x144, AF_ADJUST_UP }, /* ń */ + { 0x145, AF_ADJUST_DOWN }, /* Ņ */ + { 0x146, AF_ADJUST_DOWN }, /* ņ */ + { 0x147, AF_ADJUST_UP }, /* Ň */ + { 0x148, AF_ADJUST_UP }, /* ň */ + { 0x14C, AF_ADJUST_UP }, /* Ō */ + { 0x14D, AF_ADJUST_UP }, /* ō */ + { 0x14E, AF_ADJUST_UP }, /* Ŏ */ + { 0x14F, AF_ADJUST_UP }, /* ŏ */ + + { 0x150, AF_ADJUST_UP }, /* Ő */ + { 0x151, AF_ADJUST_UP }, /* ő */ + { 0x154, AF_ADJUST_UP }, /* Ŕ */ + { 0x155, AF_ADJUST_UP }, /* ŕ */ + { 0x156, AF_ADJUST_DOWN }, /* Ŗ */ + { 0x157, AF_ADJUST_DOWN }, /* ŗ */ + { 0x158, AF_ADJUST_UP }, /* Ř */ + { 0x159, AF_ADJUST_UP }, /* ř */ + { 0x15A, AF_ADJUST_UP }, /* Ś */ + { 0x15B, AF_ADJUST_UP }, /* ś */ + { 0x15C, AF_ADJUST_UP }, /* Ŝ */ + { 0x15D, AF_ADJUST_UP }, /* ŝ */ + { 0x15E, AF_IGNORE_CAPITAL_BOTTOM }, /* Ş */ + { 0x15F, AF_IGNORE_SMALL_BOTTOM }, /* ş */ + + { 0x160, AF_ADJUST_UP }, /* Š */ + { 0x161, AF_ADJUST_UP }, /* š */ + { 0x162, AF_IGNORE_CAPITAL_BOTTOM }, /* Ţ */ + { 0x163, AF_IGNORE_SMALL_BOTTOM }, /* ţ */ + { 0x164, AF_ADJUST_UP }, /* Ť */ + { 0x168, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ũ */ + { 0x169, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ũ */ + { 0x16A, AF_ADJUST_UP }, /* Ū */ + { 0x16B, AF_ADJUST_UP }, /* ū */ + { 0x16C, AF_ADJUST_UP }, /* Ŭ */ + { 0x16D, AF_ADJUST_UP }, /* ŭ */ + { 0x16E, AF_ADJUST_UP }, /* Ů */ + { 0x16F, AF_ADJUST_UP }, /* ů */ + + { 0x170, AF_ADJUST_UP }, /* Ű */ + { 0x171, AF_ADJUST_UP }, /* ű */ + { 0x172, AF_IGNORE_CAPITAL_BOTTOM }, /* Ų */ + { 0x173, AF_IGNORE_SMALL_BOTTOM }, /* ų */ + { 0x174, AF_ADJUST_UP }, /* Ŵ */ + { 0x175, AF_ADJUST_UP }, /* ŵ */ + { 0x176, AF_ADJUST_UP }, /* Ŷ */ + { 0x177, AF_ADJUST_UP }, /* ŷ */ + { 0x178, AF_ADJUST_UP }, /* Ÿ */ + { 0x179, AF_ADJUST_UP }, /* Ź */ + { 0x17A, AF_ADJUST_UP }, /* ź */ + { 0x17B, AF_ADJUST_UP }, /* Ż */ + { 0x17C, AF_ADJUST_UP }, /* ż */ + { 0x17D, AF_ADJUST_UP }, /* Ž */ + { 0x17E, AF_ADJUST_UP }, /* ž */ + + /* Latin Extended-B */ + { 0x187, AF_IGNORE_CAPITAL_TOP }, /* Ƈ */ + { 0x188, AF_IGNORE_SMALL_TOP }, /* ƈ */ + + { 0x1A0, AF_IGNORE_CAPITAL_TOP }, /* Ơ */ + { 0x1A1, AF_IGNORE_SMALL_TOP }, /* ơ */ + { 0x1A5, AF_IGNORE_SMALL_TOP }, /* ƥ */ + { 0x1AB, AF_IGNORE_SMALL_BOTTOM }, /* ƫ */ + { 0x1AE, AF_IGNORE_CAPITAL_BOTTOM }, /* Ʈ */ + { 0x1AF, AF_IGNORE_CAPITAL_TOP }, /* Ư */ + + { 0x1B0, AF_IGNORE_SMALL_TOP }, /* ư */ + { 0x1B4, AF_IGNORE_SMALL_TOP }, /* ƴ */ + + { 0x1C3, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ǃ */ + { 0x1C4, AF_ADJUST_UP }, /* DŽ */ +#if 0 + { 0x1C5, AF_ADJUST_UP }, /* Dž */ + { 0x1C6, AF_ADJUST_UP }, /* dž */ + { 0x1C8, AF_ADJUST_UP }, /* Lj */ + { 0x1C9, AF_ADJUST_UP }, /* lj */ + { 0x1CB, AF_ADJUST_UP }, /* Nj */ +#endif + { 0x1CC, AF_ADJUST_UP }, /* nj */ + { 0x1CD, AF_ADJUST_UP }, /* Ǎ */ + { 0x1CE, AF_ADJUST_UP }, /* ǎ */ + { 0x1CF, AF_ADJUST_UP }, /* Ǐ */ + + { 0x1D0, AF_ADJUST_UP }, /* ǐ */ + { 0x1D1, AF_ADJUST_UP }, /* Ǒ */ + { 0x1D2, AF_ADJUST_UP }, /* ǒ */ + { 0x1D3, AF_ADJUST_UP }, /* Ǔ */ + { 0x1D4, AF_ADJUST_UP }, /* ǔ */ + { 0x1D5, AF_ADJUST_UP2 }, /* Ǖ */ + { 0x1D6, AF_ADJUST_UP2 }, /* ǖ */ + { 0x1D7, AF_ADJUST_UP2 }, /* Ǘ */ + { 0x1D8, AF_ADJUST_UP2 }, /* ǘ */ + { 0x1D9, AF_ADJUST_UP2 }, /* Ǚ */ + { 0x1DA, AF_ADJUST_UP2 }, /* ǚ */ + { 0x1DB, AF_ADJUST_UP2 }, /* Ǜ */ + { 0x1DC, AF_ADJUST_UP2 }, /* ǜ */ + { 0x1DE, AF_ADJUST_UP2 }, /* Ǟ */ + { 0x1DF, AF_ADJUST_UP2 }, /* ǟ */ + + { 0x1E0, AF_ADJUST_UP2 }, /* Ǡ */ + { 0x1E1, AF_ADJUST_UP2 }, /* ǡ */ + { 0x1E2, AF_ADJUST_UP }, /* Ǣ */ + { 0x1E3, AF_ADJUST_UP }, /* ǣ */ + { 0x1E6, AF_ADJUST_UP }, /* Ǧ */ + { 0x1E7, AF_ADJUST_UP }, /* ǧ */ + { 0x1E8, AF_ADJUST_UP }, /* Ǩ */ + { 0x1E9, AF_ADJUST_UP }, /* ǩ */ + { 0x1EA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ǫ */ + { 0x1EB, AF_IGNORE_SMALL_BOTTOM }, /* ǫ */ + { 0x1EC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ǭ */ + { 0x1ED, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ǭ */ + { 0x1EE, AF_ADJUST_UP }, /* Ǯ */ + { 0x1EF, AF_ADJUST_UP }, /* ǯ */ + + { 0x1F0, AF_ADJUST_UP }, /* ǰ */ + { 0x1F4, AF_ADJUST_UP }, /* Ǵ */ + { 0x1F5, AF_ADJUST_UP }, /* ǵ */ + { 0x1F8, AF_ADJUST_UP }, /* Ǹ */ + { 0x1F9, AF_ADJUST_UP }, /* ǹ */ + { 0x1FA, AF_ADJUST_UP2 }, /* Ǻ */ + { 0x1FB, AF_ADJUST_UP2 }, /* ǻ */ + { 0x1FC, AF_ADJUST_UP }, /* Ǽ */ + { 0x1FD, AF_ADJUST_UP }, /* ǽ */ + { 0x1FE, AF_ADJUST_UP }, /* Ǿ */ + { 0x1FF, AF_ADJUST_UP }, /* ǿ */ + + { 0x200, AF_ADJUST_UP }, /* Ȁ */ + { 0x201, AF_ADJUST_UP }, /* ȁ */ + { 0x202, AF_ADJUST_UP }, /* Ȃ */ + { 0x203, AF_ADJUST_UP }, /* ȃ */ + { 0x204, AF_ADJUST_UP }, /* Ȅ */ + { 0x205, AF_ADJUST_UP }, /* ȅ */ + { 0x206, AF_ADJUST_UP }, /* Ȇ */ + { 0x207, AF_ADJUST_UP }, /* ȇ */ + { 0x208, AF_ADJUST_UP }, /* Ȉ */ + { 0x209, AF_ADJUST_UP }, /* ȉ */ + { 0x20A, AF_ADJUST_UP }, /* Ȋ */ + { 0x20B, AF_ADJUST_UP }, /* ȋ */ + { 0x20C, AF_ADJUST_UP }, /* Ȍ */ + { 0x20D, AF_ADJUST_UP }, /* ȍ */ + { 0x20E, AF_ADJUST_UP }, /* Ȏ */ + { 0x20F, AF_ADJUST_UP }, /* ȏ */ + + { 0x210, AF_ADJUST_UP }, /* Ȑ */ + { 0x211, AF_ADJUST_UP }, /* ȑ */ + { 0x212, AF_ADJUST_UP }, /* Ȓ */ + { 0x213, AF_ADJUST_UP }, /* ȓ */ + { 0x214, AF_ADJUST_UP }, /* Ȕ */ + { 0x215, AF_ADJUST_UP }, /* ȕ */ + { 0x216, AF_ADJUST_UP }, /* Ȗ */ + { 0x217, AF_ADJUST_UP }, /* ȗ */ + { 0x218, AF_ADJUST_DOWN }, /* Ș */ + { 0x219, AF_ADJUST_DOWN }, /* ș */ + { 0x21A, AF_ADJUST_DOWN }, /* Ț */ + { 0x21B, AF_ADJUST_DOWN }, /* ț */ + { 0x21E, AF_ADJUST_UP }, /* Ȟ */ + { 0x21F, AF_ADJUST_UP }, /* ȟ */ + + { 0x224, AF_IGNORE_CAPITAL_BOTTOM }, /* Ȥ */ + { 0x225, AF_IGNORE_SMALL_BOTTOM }, /* ȥ */ + { 0x226, AF_ADJUST_UP }, /* Ȧ */ + { 0x227, AF_ADJUST_UP }, /* ȧ */ + { 0x228, AF_IGNORE_CAPITAL_BOTTOM }, /* Ȩ */ + { 0x229, AF_IGNORE_SMALL_BOTTOM }, /* ȩ */ + { 0x22A, AF_ADJUST_UP2 }, /* Ȫ */ + { 0x22B, AF_ADJUST_UP2 }, /* ȫ */ + { 0x22C, AF_ADJUST_UP2 }, /* Ȭ */ + { 0x22D, AF_ADJUST_UP2 }, /* ȭ */ + { 0x22E, AF_ADJUST_UP }, /* Ȯ */ + { 0x22F, AF_ADJUST_UP }, /* ȯ */ + + { 0x230, AF_ADJUST_UP2 }, /* Ȱ */ + { 0x231, AF_ADJUST_UP2 }, /* ȱ */ + { 0x232, AF_ADJUST_UP }, /* Ȳ */ + { 0x233, AF_ADJUST_UP }, /* ȳ */ + { 0x23A, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ⱥ */ + { 0x23B, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ȼ */ + { 0x23F, AF_IGNORE_SMALL_BOTTOM }, /* ȿ */ + + { 0x240, AF_IGNORE_SMALL_BOTTOM }, /* ɀ */ + { 0x249, AF_ADJUST_UP }, /* ɉ */ + + /* IPA Extensions */ + { 0x256, AF_IGNORE_SMALL_BOTTOM }, /* ɖ */ + + { 0x260, AF_IGNORE_SMALL_TOP }, /* ɠ */ + { 0x267, AF_IGNORE_SMALL_BOTTOM }, /* ɧ */ + { 0x268, AF_ADJUST_UP }, /* ɨ */ + + { 0x272, AF_IGNORE_SMALL_BOTTOM }, /* ɲ */ + { 0x273, AF_IGNORE_SMALL_BOTTOM }, /* ɳ */ + { 0x27B, AF_IGNORE_SMALL_BOTTOM }, /* ɻ */ + { 0x27D, AF_IGNORE_SMALL_BOTTOM }, /* ɽ */ + + { 0x282, AF_IGNORE_SMALL_BOTTOM }, /* ʂ */ + { 0x288, AF_IGNORE_SMALL_BOTTOM }, /* ʈ */ + + { 0x290, AF_IGNORE_SMALL_BOTTOM }, /* ʐ */ + { 0x29B, AF_IGNORE_SMALL_TOP }, /* ʛ */ + + { 0x2A0, AF_IGNORE_SMALL_TOP }, /* ʠ */ + + /* Spacing Modifier Letters */ + { 0x2B2, AF_ADJUST_UP }, /* ʲ */ + { 0x2B5, AF_IGNORE_SMALL_BOTTOM }, /* ʵ */ + + /* Greek and Coptic */ + { 0x390, AF_ADJUST_UP2 }, /* ΐ */ + + { 0x3AA, AF_ADJUST_UP }, /* Ϊ */ + { 0x3AB, AF_ADJUST_UP }, /* Ϋ */ + { 0x3AC, AF_ADJUST_UP }, /* ά */ + { 0x3AD, AF_ADJUST_UP }, /* έ */ + { 0x3AE, AF_ADJUST_UP }, /* ή */ + { 0x3AF, AF_ADJUST_UP }, /* ί */ + + { 0x3B0, AF_ADJUST_UP2 }, /* ΰ */ + + { 0x3CA, AF_ADJUST_UP }, /* ϊ */ + { 0x3CB, AF_ADJUST_UP }, /* ϋ */ + { 0x3CC, AF_ADJUST_UP }, /* ό */ + { 0x3CD, AF_ADJUST_UP }, /* ύ */ + { 0x3CE, AF_ADJUST_UP }, /* ώ */ + { 0x3CF, AF_IGNORE_CAPITAL_BOTTOM }, /* Ϗ */ + + { 0x3D4, AF_ADJUST_UP }, /* ϔ */ + { 0x3D7, AF_IGNORE_SMALL_BOTTOM }, /* ϗ */ + { 0x3D9, AF_IGNORE_SMALL_BOTTOM }, /* ϙ */ + + { 0x3E2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ϣ */ + { 0x3E3, AF_IGNORE_SMALL_BOTTOM }, /* ϣ */ + + { 0x3F3, AF_ADJUST_UP }, /* ϳ */ + + /* Cyrillic */ + { 0x400, AF_ADJUST_UP }, /* Ѐ */ + { 0x401, AF_ADJUST_UP }, /* Ё */ + { 0x403, AF_ADJUST_UP }, /* Ѓ */ + { 0x407, AF_ADJUST_UP }, /* Ї */ + { 0x40C, AF_ADJUST_UP }, /* Ќ */ + { 0x40D, AF_ADJUST_UP }, /* Ѝ */ + { 0x40E, AF_ADJUST_UP }, /* Ў */ + { 0x40F, AF_IGNORE_CAPITAL_BOTTOM }, /* Џ */ + + { 0x419, AF_ADJUST_UP }, /* Й */ + + { 0x426, AF_IGNORE_CAPITAL_BOTTOM }, /* Ц */ + { 0x429, AF_IGNORE_CAPITAL_BOTTOM }, /* Щ */ + + { 0x439, AF_ADJUST_UP }, /* й */ + + { 0x446, AF_IGNORE_SMALL_BOTTOM }, /* ц */ + { 0x449, AF_IGNORE_SMALL_BOTTOM }, /* щ */ + + { 0x450, AF_ADJUST_UP }, /* ѐ */ + { 0x451, AF_ADJUST_UP }, /* ё */ + { 0x453, AF_ADJUST_UP }, /* ѓ */ + { 0x456, AF_ADJUST_UP }, /* і */ + { 0x457, AF_ADJUST_UP }, /* ї */ + { 0x458, AF_ADJUST_UP }, /* ј */ + { 0x45C, AF_ADJUST_UP }, /* ќ */ + { 0x45D, AF_ADJUST_UP }, /* ѝ */ + { 0x45E, AF_ADJUST_UP }, /* ў */ + { 0x45F, AF_IGNORE_SMALL_BOTTOM }, /* џ */ + + { 0x476, AF_ADJUST_UP }, /* Ѷ */ + { 0x477, AF_ADJUST_UP }, /* ѷ */ + { 0x47C, AF_ADJUST_UP2 }, /* Ѽ */ + { 0x47D, AF_ADJUST_UP2 }, /* ѽ */ + { 0x47E, AF_ADJUST_UP }, /* Ѿ */ + { 0x47F, AF_ADJUST_UP }, /* ѿ */ + + { 0x480, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҁ */ + { 0x481, AF_IGNORE_SMALL_BOTTOM }, /* ҁ */ + { 0x48A, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ҋ */ + { 0x48B, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ҋ */ + + { 0x490, AF_IGNORE_CAPITAL_TOP }, /* Ґ */ + { 0x491, AF_IGNORE_SMALL_TOP }, /* ґ */ + { 0x496, AF_IGNORE_CAPITAL_BOTTOM }, /* Җ */ + { 0x497, AF_IGNORE_SMALL_BOTTOM }, /* җ */ + { 0x498, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҙ */ + { 0x499, AF_IGNORE_SMALL_BOTTOM }, /* ҙ */ + { 0x49A, AF_IGNORE_CAPITAL_BOTTOM }, /* Қ */ + { 0x49B, AF_IGNORE_SMALL_BOTTOM }, /* қ */ + + { 0x4A2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ң */ + { 0x4A3, AF_IGNORE_SMALL_BOTTOM }, /* ң */ + { 0x4AA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҫ */ + { 0x4AB, AF_IGNORE_SMALL_BOTTOM }, /* ҫ */ + { 0x4AC, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҭ */ + { 0x4AD, AF_IGNORE_SMALL_BOTTOM }, /* ҭ */ + + { 0x4B2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҳ */ + { 0x4B3, AF_IGNORE_SMALL_BOTTOM }, /* ҳ */ + { 0x4B4, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҵ */ + { 0x4B5, AF_IGNORE_SMALL_BOTTOM }, /* ҵ */ + { 0x4B6, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҷ */ + { 0x4B7, AF_IGNORE_SMALL_BOTTOM }, /* ҷ */ + { 0x4BE, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҿ */ + { 0x4BF, AF_IGNORE_SMALL_BOTTOM }, /* ҿ */ + + { 0x4C1, AF_ADJUST_UP }, /* Ӂ */ + { 0x4C2, AF_ADJUST_UP }, /* ӂ */ + { 0x4C5, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӆ */ + { 0x4C6, AF_IGNORE_SMALL_BOTTOM }, /* ӆ */ + { 0x4C9, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӊ */ + { 0x4CA, AF_IGNORE_SMALL_BOTTOM }, /* ӊ */ + { 0x4CB, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӌ */ + { 0x4CC, AF_IGNORE_SMALL_BOTTOM }, /* ӌ */ + { 0x4CD, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӎ */ + { 0x4CE, AF_IGNORE_SMALL_BOTTOM }, /* ӎ */ + + { 0x4D0, AF_ADJUST_UP }, /* Ӑ */ + { 0x4D1, AF_ADJUST_UP }, /* ӑ */ + { 0x4D2, AF_ADJUST_UP }, /* Ӓ */ + { 0x4D3, AF_ADJUST_UP }, /* ӓ */ + { 0x4D6, AF_ADJUST_UP }, /* Ӗ */ + { 0x4D7, AF_ADJUST_UP }, /* ӗ */ + { 0x4DA, AF_ADJUST_UP }, /* Ӛ */ + { 0x4DB, AF_ADJUST_UP }, /* ӛ */ + { 0x4DC, AF_ADJUST_UP }, /* Ӝ */ + { 0x4DD, AF_ADJUST_UP }, /* ӝ */ + { 0x4DE, AF_ADJUST_UP }, /* Ӟ */ + { 0x4DF, AF_ADJUST_UP }, /* ӟ */ + + { 0x4E2, AF_ADJUST_UP }, /* Ӣ */ + { 0x4E3, AF_ADJUST_UP }, /* ӣ */ + { 0x4E4, AF_ADJUST_UP }, /* Ӥ */ + { 0x4E5, AF_ADJUST_UP }, /* ӥ */ + { 0x4E6, AF_ADJUST_UP }, /* Ӧ */ + { 0x4E7, AF_ADJUST_UP }, /* ӧ */ + { 0x4EA, AF_ADJUST_UP }, /* Ӫ */ + { 0x4EB, AF_ADJUST_UP }, /* ӫ */ + { 0x4EC, AF_ADJUST_UP }, /* Ӭ */ + { 0x4ED, AF_ADJUST_UP }, /* ӭ */ + { 0x4EE, AF_ADJUST_UP }, /* Ӯ */ + { 0x4EF, AF_ADJUST_UP }, /* ӯ */ + + { 0x4F0, AF_ADJUST_UP }, /* Ӱ */ + { 0x4F1, AF_ADJUST_UP }, /* ӱ */ + { 0x4F2, AF_ADJUST_UP }, /* Ӳ */ + { 0x4F3, AF_ADJUST_UP }, /* ӳ */ + { 0x4F4, AF_ADJUST_UP }, /* Ӵ */ + { 0x4F5, AF_ADJUST_UP }, /* ӵ */ + { 0x4F6, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӷ */ + { 0x4F7, AF_IGNORE_SMALL_BOTTOM }, /* ӷ */ + { 0x4F8, AF_ADJUST_UP }, /* Ӹ */ + { 0x4F9, AF_ADJUST_UP }, /* ӹ */ + { 0x4FA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӻ */ + { 0x4FB, AF_IGNORE_SMALL_BOTTOM }, /* ӻ */ + + /* Cyrillic Supplement */ + { 0x506, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԇ */ + { 0x507, AF_IGNORE_SMALL_BOTTOM }, /* ԇ */ + + { 0x524, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԥ */ + { 0x525, AF_IGNORE_SMALL_BOTTOM }, /* ԥ */ + { 0x526, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԧ */ + { 0x527, AF_IGNORE_SMALL_BOTTOM }, /* ԧ */ + { 0x52E, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԯ */ + { 0x52F, AF_IGNORE_SMALL_BOTTOM }, /* ԯ */ + + /* Cherokee */ + { 0x13A5, AF_ADJUST_UP }, /* Ꭵ */ + + /* Phonetic Extensions */ + { 0x1D09, AF_ADJUST_DOWN }, /* ᴉ */ + + { 0x1D4E, AF_ADJUST_DOWN }, /* ᵎ */ + + { 0x1D51, AF_IGNORE_SMALL_BOTTOM }, /* ᵑ */ + + { 0x1D62, AF_ADJUST_UP }, /* ᵢ */ + + /* Phonetic Extensions Supplement */ + { 0x1D80, AF_IGNORE_SMALL_BOTTOM }, /* ᶀ */ + { 0x1D81, AF_IGNORE_SMALL_BOTTOM }, /* ᶁ */ + { 0x1D82, AF_IGNORE_SMALL_BOTTOM }, /* ᶂ */ + { 0x1D84, AF_IGNORE_SMALL_BOTTOM }, /* ᶄ */ + { 0x1D85, AF_IGNORE_SMALL_BOTTOM }, /* ᶅ */ + { 0x1D86, AF_IGNORE_SMALL_BOTTOM }, /* ᶆ */ + { 0x1D87, AF_IGNORE_SMALL_BOTTOM }, /* ᶇ */ + { 0x1D89, AF_IGNORE_SMALL_BOTTOM }, /* ᶉ */ + { 0x1D8A, AF_IGNORE_SMALL_BOTTOM }, /* ᶊ */ + { 0x1D8C, AF_IGNORE_SMALL_BOTTOM }, /* ᶌ */ + { 0x1D8D, AF_IGNORE_SMALL_BOTTOM }, /* ᶍ */ + { 0x1D8E, AF_IGNORE_SMALL_BOTTOM }, /* ᶎ */ + { 0x1D8F, AF_IGNORE_SMALL_BOTTOM }, /* ᶏ */ + + { 0x1D90, AF_IGNORE_SMALL_BOTTOM }, /* ᶐ */ + { 0x1D91, AF_IGNORE_SMALL_BOTTOM }, /* ᶑ */ + { 0x1D92, AF_IGNORE_SMALL_BOTTOM }, /* ᶒ */ + { 0x1D93, AF_IGNORE_SMALL_BOTTOM }, /* ᶓ */ + { 0x1D94, AF_IGNORE_SMALL_BOTTOM }, /* ᶔ */ + { 0x1D95, AF_IGNORE_SMALL_BOTTOM }, /* ᶕ */ + { 0x1D96, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ᶖ */ + { 0x1D97, AF_IGNORE_SMALL_BOTTOM }, /* ᶗ */ + { 0x1D98, AF_IGNORE_SMALL_BOTTOM }, /* ᶘ */ + { 0x1D99, AF_IGNORE_SMALL_BOTTOM }, /* ᶙ */ + { 0x1D9A, AF_IGNORE_SMALL_BOTTOM }, /* ᶚ */ + + { 0x1DA4, AF_ADJUST_UP }, /* ᶤ */ + { 0x1DA8, AF_ADJUST_UP }, /* ᶨ */ + { 0x1DA9, AF_IGNORE_SMALL_BOTTOM }, /* ᶩ */ + { 0x1DAA, AF_IGNORE_SMALL_BOTTOM }, /* ᶪ */ + { 0x1DAC, AF_IGNORE_SMALL_BOTTOM }, /* ᶬ */ + { 0x1DAE, AF_IGNORE_SMALL_BOTTOM }, /* ᶮ */ + { 0x1DAF, AF_IGNORE_SMALL_BOTTOM }, /* ᶯ */ + + { 0x1DB3, AF_IGNORE_SMALL_BOTTOM }, /* ᶳ */ + { 0x1DB5, AF_IGNORE_SMALL_BOTTOM }, /* ᶵ */ + { 0x1DBC, AF_IGNORE_SMALL_BOTTOM }, /* ᶼ */ + + /* Latin Extended Additional */ + { 0x1E00, AF_ADJUST_DOWN }, /* Ḁ */ + { 0x1E01, AF_ADJUST_DOWN }, /* ḁ */ + { 0x1E02, AF_ADJUST_UP }, /* Ḃ */ + { 0x1E03, AF_ADJUST_UP }, /* ḃ */ + { 0x1E04, AF_ADJUST_DOWN }, /* Ḅ */ + { 0x1E05, AF_ADJUST_DOWN }, /* ḅ */ + { 0x1E06, AF_ADJUST_DOWN }, /* Ḇ */ + { 0x1E07, AF_ADJUST_DOWN }, /* ḇ */ + { 0x1E08, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ḉ */ + { 0x1E09, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ḉ */ + { 0x1E0A, AF_ADJUST_UP }, /* Ḋ */ + { 0x1E0B, AF_ADJUST_UP }, /* ḋ */ + { 0x1E0C, AF_ADJUST_DOWN }, /* Ḍ */ + { 0x1E0D, AF_ADJUST_DOWN }, /* ḍ */ + { 0x1E0E, AF_ADJUST_DOWN }, /* Ḏ */ + { 0x1E0F, AF_ADJUST_DOWN }, /* ḏ */ + + { 0x1E10, AF_ADJUST_DOWN }, /* Ḑ */ + { 0x1E11, AF_ADJUST_DOWN }, /* ḑ */ + { 0x1E12, AF_ADJUST_DOWN }, /* Ḓ */ + { 0x1E13, AF_ADJUST_DOWN }, /* ḓ */ + { 0x1E14, AF_ADJUST_UP2 }, /* Ḕ */ + { 0x1E15, AF_ADJUST_UP2 }, /* ḕ */ + { 0x1E16, AF_ADJUST_UP2 }, /* Ḗ */ + { 0x1E17, AF_ADJUST_UP2 }, /* ḗ */ + { 0x1E18, AF_ADJUST_DOWN }, /* Ḙ */ + { 0x1E19, AF_ADJUST_DOWN }, /* ḙ */ + { 0x1E1A, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ḛ */ + { 0x1E1B, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ḛ */ + { 0x1E1C, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ḝ */ + { 0x1E1D, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ḝ */ + { 0x1E1E, AF_ADJUST_UP }, /* Ḟ */ + { 0x1E1F, AF_ADJUST_UP }, /* ḟ */ + + { 0x1E20, AF_ADJUST_UP }, /* Ḡ */ + { 0x1E21, AF_ADJUST_UP }, /* ḡ */ + { 0x1E22, AF_ADJUST_UP }, /* Ḣ */ + { 0x1E23, AF_ADJUST_UP }, /* ḣ */ + { 0x1E24, AF_ADJUST_DOWN }, /* Ḥ */ + { 0x1E25, AF_ADJUST_DOWN }, /* ḥ */ + { 0x1E26, AF_ADJUST_UP }, /* Ḧ */ + { 0x1E27, AF_ADJUST_UP }, /* ḧ */ + { 0x1E28, AF_IGNORE_CAPITAL_BOTTOM }, /* Ḩ */ + { 0x1E29, AF_IGNORE_SMALL_BOTTOM }, /* ḩ */ + { 0x1E2A, AF_ADJUST_DOWN }, /* Ḫ */ + { 0x1E2B, AF_ADJUST_DOWN }, /* ḫ */ + { 0x1E2C, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ḭ */ + { 0x1E2D, AF_ADJUST_UP | AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ḭ */ + { 0x1E2E, AF_ADJUST_UP2 }, /* Ḯ */ + { 0x1E2F, AF_ADJUST_UP2 }, /* ḯ */ + + { 0x1E30, AF_ADJUST_UP }, /* Ḱ */ + { 0x1E31, AF_ADJUST_UP }, /* ḱ */ + { 0x1E32, AF_ADJUST_DOWN }, /* Ḳ */ + { 0x1E33, AF_ADJUST_DOWN }, /* ḳ */ + { 0x1E34, AF_ADJUST_DOWN }, /* Ḵ */ + { 0x1E35, AF_ADJUST_DOWN }, /* ḵ */ + { 0x1E36, AF_ADJUST_DOWN }, /* Ḷ */ + { 0x1E37, AF_ADJUST_DOWN }, /* ḷ */ + { 0x1E38, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ḹ */ + { 0x1E39, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ḹ */ + { 0x1E3A, AF_ADJUST_DOWN }, /* Ḻ */ + { 0x1E3B, AF_ADJUST_DOWN }, /* ḻ */ + { 0x1E3C, AF_ADJUST_DOWN }, /* Ḽ */ + { 0x1E3D, AF_ADJUST_DOWN }, /* ḽ */ + { 0x1E3E, AF_ADJUST_UP }, /* Ḿ */ + { 0x1E3F, AF_ADJUST_UP }, /* ḿ */ + + { 0x1E40, AF_ADJUST_UP }, /* Ṁ */ + { 0x1E41, AF_ADJUST_UP }, /* ṁ */ + { 0x1E42, AF_ADJUST_DOWN }, /* Ṃ */ + { 0x1E43, AF_ADJUST_DOWN }, /* ṃ */ + { 0x1E44, AF_ADJUST_UP }, /* Ṅ */ + { 0x1E45, AF_ADJUST_UP }, /* ṅ */ + { 0x1E46, AF_ADJUST_DOWN }, /* Ṇ */ + { 0x1E47, AF_ADJUST_DOWN }, /* ṇ */ + { 0x1E48, AF_ADJUST_DOWN }, /* Ṉ */ + { 0x1E49, AF_ADJUST_DOWN }, /* ṉ */ + { 0x1E4A, AF_ADJUST_DOWN }, /* Ṋ */ + { 0x1E4B, AF_ADJUST_DOWN }, /* ṋ */ + { 0x1E4C, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṍ */ + { 0x1E4D, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṍ */ + { 0x1E4E, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṏ */ + { 0x1E4F, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṏ */ + + { 0x1E50, AF_ADJUST_UP2 }, /* Ṑ */ + { 0x1E51, AF_ADJUST_UP2 }, /* ṑ */ + { 0x1E52, AF_ADJUST_UP2 }, /* Ṓ */ + { 0x1E53, AF_ADJUST_UP2 }, /* ṓ */ + { 0x1E54, AF_ADJUST_UP }, /* Ṕ */ + { 0x1E55, AF_ADJUST_UP }, /* ṕ */ + { 0x1E56, AF_ADJUST_UP }, /* Ṗ */ + { 0x1E57, AF_ADJUST_UP }, /* ṗ */ + { 0x1E58, AF_ADJUST_UP }, /* Ṙ */ + { 0x1E59, AF_ADJUST_UP }, /* ṙ */ + { 0x1E5A, AF_ADJUST_DOWN }, /* Ṛ */ + { 0x1E5B, AF_ADJUST_DOWN }, /* ṛ */ + { 0x1E5C, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ṝ */ + { 0x1E5D, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ṝ */ + { 0x1E5E, AF_ADJUST_DOWN }, /* Ṟ */ + { 0x1E5F, AF_ADJUST_DOWN }, /* ṟ */ + + { 0x1E60, AF_ADJUST_UP }, /* Ṡ */ + { 0x1E61, AF_ADJUST_UP }, /* ṡ */ + { 0x1E62, AF_ADJUST_DOWN }, /* Ṣ */ + { 0x1E63, AF_ADJUST_DOWN }, /* ṣ */ + { 0x1E64, AF_ADJUST_UP }, /* Ṥ */ + { 0x1E65, AF_ADJUST_UP }, /* ṥ */ + { 0x1E66, AF_ADJUST_UP }, /* Ṧ */ + { 0x1E67, AF_ADJUST_UP }, /* ṧ */ + { 0x1E68, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ṩ */ + { 0x1E69, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ṩ */ + { 0x1E6A, AF_ADJUST_UP }, /* Ṫ */ + { 0x1E6B, AF_ADJUST_UP }, /* ṫ */ + { 0x1E6C, AF_ADJUST_DOWN }, /* Ṭ */ + { 0x1E6D, AF_ADJUST_DOWN }, /* ṭ */ + { 0x1E6E, AF_ADJUST_DOWN }, /* Ṯ */ + { 0x1E6F, AF_ADJUST_DOWN }, /* ṯ */ + + { 0x1E70, AF_ADJUST_DOWN }, /* Ṱ */ + { 0x1E71, AF_ADJUST_DOWN }, /* ṱ */ + { 0x1E72, AF_ADJUST_DOWN }, /* Ṳ */ + { 0x1E73, AF_ADJUST_DOWN }, /* ṳ */ + { 0x1E74, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ṵ */ + { 0x1E75, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ṵ */ + { 0x1E76, AF_ADJUST_DOWN }, /* Ṷ */ + { 0x1E77, AF_ADJUST_DOWN }, /* ṷ */ + { 0x1E78, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṹ */ + { 0x1E79, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṹ */ + { 0x1E7A, AF_ADJUST_UP2 }, /* Ṻ */ + { 0x1E7B, AF_ADJUST_UP2 }, /* ṻ */ + { 0x1E7C, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ṽ */ + { 0x1E7D, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ṽ */ + { 0x1E7E, AF_ADJUST_DOWN }, /* Ṿ */ + { 0x1E7F, AF_ADJUST_DOWN }, /* ṿ */ + + { 0x1E80, AF_ADJUST_UP }, /* Ẁ */ + { 0x1E81, AF_ADJUST_UP }, /* ẁ */ + { 0x1E82, AF_ADJUST_UP }, /* Ẃ */ + { 0x1E83, AF_ADJUST_UP }, /* ẃ */ + { 0x1E84, AF_ADJUST_UP }, /* Ẅ */ + { 0x1E85, AF_ADJUST_UP }, /* ẅ */ + { 0x1E86, AF_ADJUST_UP }, /* Ẇ */ + { 0x1E87, AF_ADJUST_UP }, /* ẇ */ + { 0x1E88, AF_ADJUST_DOWN }, /* Ẉ */ + { 0x1E89, AF_ADJUST_DOWN }, /* ẉ */ + { 0x1E8A, AF_ADJUST_UP }, /* Ẋ */ + { 0x1E8B, AF_ADJUST_UP }, /* ẋ */ + { 0x1E8C, AF_ADJUST_UP }, /* Ẍ */ + { 0x1E8D, AF_ADJUST_UP }, /* ẍ */ + { 0x1E8E, AF_ADJUST_UP }, /* Ẏ */ + { 0x1E8F, AF_ADJUST_UP }, /* ẏ */ + + { 0x1E90, AF_ADJUST_UP }, /* Ẑ */ + { 0x1E91, AF_ADJUST_UP }, /* ẑ */ + { 0x1E92, AF_ADJUST_DOWN }, /* Ẓ */ + { 0x1E93, AF_ADJUST_DOWN }, /* ẓ */ + { 0x1E94, AF_ADJUST_DOWN }, /* Ẕ */ + { 0x1E95, AF_ADJUST_DOWN }, /* ẕ */ + { 0x1E96, AF_ADJUST_DOWN }, /* ẖ */ + { 0x1E97, AF_ADJUST_UP }, /* ẗ */ + { 0x1E98, AF_ADJUST_UP }, /* ẘ */ + { 0x1E99, AF_ADJUST_UP }, /* ẙ */ + { 0x1E9A, AF_ADJUST_UP }, /* ẚ */ + { 0x1E9B, AF_ADJUST_UP }, /* ẛ */ + + { 0x1EA0, AF_ADJUST_DOWN }, /* Ạ */ + { 0x1EA1, AF_ADJUST_DOWN }, /* ạ */ + { 0x1EA2, AF_ADJUST_UP }, /* Ả */ + { 0x1EA3, AF_ADJUST_UP }, /* ả */ + { 0x1EA4, AF_ADJUST_UP2 }, /* Ấ */ + { 0x1EA5, AF_ADJUST_UP2 }, /* ấ */ + { 0x1EA6, AF_ADJUST_UP2 }, /* Ầ */ + { 0x1EA7, AF_ADJUST_UP2 }, /* ầ */ + { 0x1EA8, AF_ADJUST_UP2 }, /* Ẩ */ + { 0x1EA9, AF_ADJUST_UP2 }, /* ẩ */ + { 0x1EAA, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ẫ */ + { 0x1EAB, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ẫ */ + { 0x1EAC, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ậ */ + { 0x1EAD, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ậ */ + { 0x1EAE, AF_ADJUST_UP2 }, /* Ắ */ + { 0x1EAF, AF_ADJUST_UP2 }, /* ắ */ + + { 0x1EB0, AF_ADJUST_UP2 }, /* Ằ */ + { 0x1EB1, AF_ADJUST_UP2 }, /* ằ */ + { 0x1EB2, AF_ADJUST_UP2 }, /* Ẳ */ + { 0x1EB3, AF_ADJUST_UP2 }, /* ẳ */ + { 0x1EB4, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ẵ */ + { 0x1EB5, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ẵ */ + { 0x1EB6, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ặ */ + { 0x1EB7, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ặ */ + { 0x1EB8, AF_ADJUST_DOWN }, /* Ẹ */ + { 0x1EB9, AF_ADJUST_DOWN }, /* ẹ */ + { 0x1EBA, AF_ADJUST_UP }, /* Ẻ */ + { 0x1EBB, AF_ADJUST_UP }, /* ẻ */ + { 0x1EBC, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ẽ */ + { 0x1EBD, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ẽ */ + { 0x1EBE, AF_ADJUST_UP2 }, /* Ế */ + { 0x1EBF, AF_ADJUST_UP2 }, /* ế */ + + { 0x1EC0, AF_ADJUST_UP2 }, /* Ề */ + { 0x1EC1, AF_ADJUST_UP2 }, /* ề */ + { 0x1EC2, AF_ADJUST_UP2 }, /* Ể */ + { 0x1EC3, AF_ADJUST_UP2 }, /* ể */ + { 0x1EC4, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ễ */ + { 0x1EC5, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ễ */ + { 0x1EC6, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ệ */ + { 0x1EC7, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ệ */ + { 0x1EC8, AF_ADJUST_UP }, /* Ỉ */ + { 0x1EC9, AF_ADJUST_UP }, /* ỉ */ + { 0x1ECA, AF_ADJUST_DOWN }, /* Ị */ + { 0x1ECB, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ị */ + { 0x1ECC, AF_ADJUST_DOWN }, /* Ọ */ + { 0x1ECD, AF_ADJUST_DOWN }, /* ọ */ + { 0x1ECE, AF_ADJUST_UP }, /* Ỏ */ + { 0x1ECF, AF_ADJUST_UP }, /* ỏ */ + + { 0x1ED0, AF_ADJUST_UP2 }, /* Ố */ + { 0x1ED1, AF_ADJUST_UP2 }, /* ố */ + { 0x1ED2, AF_ADJUST_UP2 }, /* Ồ */ + { 0x1ED3, AF_ADJUST_UP2 }, /* ồ */ + { 0x1ED4, AF_ADJUST_UP2 }, /* Ổ */ + { 0x1ED5, AF_ADJUST_UP2 }, /* ổ */ + { 0x1ED6, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ỗ */ + { 0x1ED7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ỗ */ + { 0x1ED8, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ộ */ + { 0x1ED9, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ộ */ + { 0x1EDA, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ớ */ + { 0x1EDB, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ớ */ + { 0x1EDC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ờ */ + { 0x1EDD, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ờ */ + { 0x1EDE, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ở */ + { 0x1EDF, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ở */ + + { 0x1EE0, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_CAPITAL_TOP }, /* Ỡ */ + { 0x1EE1, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_SMALL_TOP }, /* ỡ */ + { 0x1EE2, AF_ADJUST_DOWN | AF_IGNORE_CAPITAL_TOP }, /* Ợ */ + { 0x1EE3, AF_ADJUST_DOWN | AF_IGNORE_SMALL_TOP }, /* ợ */ + { 0x1EE4, AF_ADJUST_DOWN }, /* Ụ */ + { 0x1EE5, AF_ADJUST_DOWN }, /* ụ */ + { 0x1EE6, AF_ADJUST_UP }, /* Ủ */ + { 0x1EE7, AF_ADJUST_UP }, /* ủ */ + { 0x1EE8, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ứ */ + { 0x1EE9, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ứ */ + { 0x1EEA, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ừ */ + { 0x1EEB, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ừ */ + { 0x1EEC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ử */ + { 0x1EED, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ử */ + { 0x1EEE, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_CAPITAL_TOP }, /* Ữ */ + { 0x1EEF, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_SMALL_TOP }, /* ữ */ + + { 0x1EF0, AF_ADJUST_DOWN | AF_IGNORE_CAPITAL_TOP }, /* Ự */ + { 0x1EF1, AF_ADJUST_DOWN | AF_IGNORE_SMALL_TOP }, /* ự */ + { 0x1EF2, AF_ADJUST_UP }, /* Ỳ */ + { 0x1EF3, AF_ADJUST_UP }, /* ỳ */ + { 0x1EF4, AF_ADJUST_DOWN }, /* Ỵ */ + { 0x1EF5, AF_ADJUST_DOWN }, /* ỵ */ + { 0x1EF6, AF_ADJUST_UP }, /* Ỷ */ + { 0x1EF7, AF_ADJUST_UP }, /* ỷ */ + { 0x1EF8, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ỹ */ + { 0x1EF9, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ỹ */ + + /* Greek Extended */ + { 0x1F00, AF_ADJUST_UP }, /* ἀ */ + { 0x1F01, AF_ADJUST_UP }, /* ἁ */ + { 0x1F02, AF_ADJUST_UP }, /* ἂ */ + { 0x1F03, AF_ADJUST_UP }, /* ἃ */ + { 0x1F04, AF_ADJUST_UP }, /* ἄ */ + { 0x1F05, AF_ADJUST_UP }, /* ἅ */ + { 0x1F06, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἆ */ + { 0x1F07, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἇ */ + + { 0x1F10, AF_ADJUST_UP }, /* ἐ */ + { 0x1F11, AF_ADJUST_UP }, /* ἑ */ + { 0x1F12, AF_ADJUST_UP }, /* ἒ */ + { 0x1F13, AF_ADJUST_UP }, /* ἓ */ + { 0x1F14, AF_ADJUST_UP }, /* ἔ */ + { 0x1F15, AF_ADJUST_UP }, /* ἕ */ + + { 0x1F20, AF_ADJUST_UP }, /* ἠ */ + { 0x1F21, AF_ADJUST_UP }, /* ἡ */ + { 0x1F22, AF_ADJUST_UP }, /* ἢ */ + { 0x1F23, AF_ADJUST_UP }, /* ἣ */ + { 0x1F24, AF_ADJUST_UP }, /* ἤ */ + { 0x1F25, AF_ADJUST_UP }, /* ἥ */ + { 0x1F26, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἦ */ + { 0x1F27, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἧ */ + + { 0x1F30, AF_ADJUST_UP }, /* ἰ */ + { 0x1F31, AF_ADJUST_UP }, /* ἱ */ + { 0x1F32, AF_ADJUST_UP }, /* ἲ */ + { 0x1F33, AF_ADJUST_UP }, /* ἳ */ + { 0x1F34, AF_ADJUST_UP }, /* ἴ */ + { 0x1F35, AF_ADJUST_UP }, /* ἵ */ + { 0x1F36, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἶ */ + { 0x1F37, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἷ */ + + { 0x1F40, AF_ADJUST_UP }, /* ὀ */ + { 0x1F41, AF_ADJUST_UP }, /* ὁ */ + { 0x1F42, AF_ADJUST_UP }, /* ὂ */ + { 0x1F43, AF_ADJUST_UP }, /* ὃ */ + { 0x1F44, AF_ADJUST_UP }, /* ὄ */ + { 0x1F45, AF_ADJUST_UP }, /* ὅ */ + + { 0x1F50, AF_ADJUST_UP }, /* ὐ */ + { 0x1F51, AF_ADJUST_UP }, /* ὑ */ + { 0x1F52, AF_ADJUST_UP }, /* ὒ */ + { 0x1F53, AF_ADJUST_UP }, /* ὓ */ + { 0x1F54, AF_ADJUST_UP }, /* ὔ */ + { 0x1F55, AF_ADJUST_UP }, /* ὕ */ + { 0x1F56, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὖ */ + { 0x1F57, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὗ */ + + { 0x1F60, AF_ADJUST_UP }, /* ὠ */ + { 0x1F61, AF_ADJUST_UP }, /* ὡ */ + { 0x1F62, AF_ADJUST_UP }, /* ὢ */ + { 0x1F63, AF_ADJUST_UP }, /* ὣ */ + { 0x1F64, AF_ADJUST_UP }, /* ὤ */ + { 0x1F65, AF_ADJUST_UP }, /* ὥ */ + { 0x1F66, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὦ */ + { 0x1F67, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὧ */ + + { 0x1F70, AF_ADJUST_UP }, /* ὰ */ + { 0x1F71, AF_ADJUST_UP }, /* ά */ + { 0x1F72, AF_ADJUST_UP }, /* ὲ */ + { 0x1F73, AF_ADJUST_UP }, /* έ */ + { 0x1F74, AF_ADJUST_UP }, /* ὴ */ + { 0x1F75, AF_ADJUST_UP }, /* ή */ + { 0x1F76, AF_ADJUST_UP }, /* ὶ */ + { 0x1F77, AF_ADJUST_UP }, /* ί */ + { 0x1F78, AF_ADJUST_UP }, /* ὸ */ + { 0x1F79, AF_ADJUST_UP }, /* ό */ + { 0x1F7A, AF_ADJUST_UP }, /* ὺ */ + { 0x1F7B, AF_ADJUST_UP }, /* ύ */ + { 0x1F7C, AF_ADJUST_UP }, /* ὼ */ + { 0x1F7D, AF_ADJUST_UP }, /* ώ */ + + { 0x1F80, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾀ */ + { 0x1F81, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾁ */ + { 0x1F82, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾂ */ + { 0x1F83, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾃ */ + { 0x1F84, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾄ */ + { 0x1F85, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾅ */ + { 0x1F86, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾆ */ + { 0x1F87, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾇ */ + { 0x1F88, AF_ADJUST_DOWN }, /* ᾈ */ + { 0x1F89, AF_ADJUST_DOWN }, /* ᾉ */ + { 0x1F8A, AF_ADJUST_DOWN }, /* ᾊ */ + { 0x1F8B, AF_ADJUST_DOWN }, /* ᾋ */ + { 0x1F8C, AF_ADJUST_DOWN }, /* ᾌ */ + { 0x1F8D, AF_ADJUST_DOWN }, /* ᾍ */ + { 0x1F8E, AF_ADJUST_DOWN }, /* ᾎ */ + { 0x1F8F, AF_ADJUST_DOWN }, /* ᾏ */ + + { 0x1F90, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾐ */ + { 0x1F91, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾑ */ + { 0x1F92, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾒ */ + { 0x1F93, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾓ */ + { 0x1F94, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾔ */ + { 0x1F95, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾕ */ + { 0x1F96, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾖ */ + { 0x1F97, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾗ */ + { 0x1F98, AF_ADJUST_DOWN }, /* ᾘ */ + { 0x1F99, AF_ADJUST_DOWN }, /* ᾙ */ + { 0x1F9A, AF_ADJUST_DOWN }, /* ᾚ */ + { 0x1F9B, AF_ADJUST_DOWN }, /* ᾛ */ + { 0x1F9C, AF_ADJUST_DOWN }, /* ᾜ */ + { 0x1F9D, AF_ADJUST_DOWN }, /* ᾝ */ + { 0x1F9E, AF_ADJUST_DOWN }, /* ᾞ */ + { 0x1F9F, AF_ADJUST_DOWN }, /* ᾟ */ + + { 0x1FA0, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾠ */ + { 0x1FA1, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾡ */ + { 0x1FA2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾢ */ + { 0x1FA3, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾣ */ + { 0x1FA4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾤ */ + { 0x1FA5, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾥ */ + { 0x1FA6, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾦ */ + { 0x1FA7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾧ */ + { 0x1FA8, AF_ADJUST_DOWN }, /* ᾨ */ + { 0x1FA9, AF_ADJUST_DOWN }, /* ᾩ */ + { 0x1FAA, AF_ADJUST_DOWN }, /* ᾪ */ + { 0x1FAB, AF_ADJUST_DOWN }, /* ᾫ */ + { 0x1FAC, AF_ADJUST_DOWN }, /* ᾬ */ + { 0x1FAD, AF_ADJUST_DOWN }, /* ᾭ */ + { 0x1FAE, AF_ADJUST_DOWN }, /* ᾮ */ + { 0x1FAF, AF_ADJUST_DOWN }, /* ᾯ */ + + { 0x1FB0, AF_ADJUST_UP }, /* ᾰ */ + { 0x1FB1, AF_ADJUST_UP }, /* ᾱ */ + { 0x1FB2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾲ */ + { 0x1FB3, AF_ADJUST_DOWN }, /* ᾳ */ + { 0x1FB4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾴ */ + { 0x1FB6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ᾶ */ + { 0x1FB7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾷ */ + { 0x1FB8, AF_ADJUST_UP }, /* Ᾰ */ + { 0x1FB9, AF_ADJUST_UP }, /* Ᾱ */ + { 0x1FBC, AF_ADJUST_DOWN }, /* ᾼ */ + + { 0x1FC2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῂ */ + { 0x1FC3, AF_ADJUST_DOWN }, /* ῃ */ + { 0x1FC4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῄ */ + { 0x1FC6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῆ */ + { 0x1FC7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ῇ */ + { 0x1FCC, AF_ADJUST_DOWN }, /* ῌ */ + + { 0x1FD0, AF_ADJUST_UP }, /* ῐ */ + { 0x1FD1, AF_ADJUST_UP }, /* ῑ */ + { 0x1FD2, AF_ADJUST_UP2 }, /* ῒ */ + { 0x1FD3, AF_ADJUST_UP2 }, /* ΐ */ + { 0x1FD6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῖ */ + { 0x1FD7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ῗ */ + { 0x1FD8, AF_ADJUST_UP }, /* Ῐ */ + { 0x1FD9, AF_ADJUST_UP }, /* Ῑ */ + + { 0x1FE0, AF_ADJUST_UP }, /* ῠ */ + { 0x1FE1, AF_ADJUST_UP }, /* ῡ */ + { 0x1FE2, AF_ADJUST_UP2 }, /* ῢ */ + { 0x1FE3, AF_ADJUST_UP2 }, /* ΰ */ + { 0x1FE4, AF_ADJUST_UP }, /* ῤ */ + { 0x1FE5, AF_ADJUST_UP }, /* ῥ */ + { 0x1FE6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῦ */ + { 0x1FE7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ῧ */ + { 0x1FE8, AF_ADJUST_UP }, /* Ῠ */ + { 0x1FE9, AF_ADJUST_UP }, /* Ῡ */ + { 0x1FF2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῲ */ + { 0x1FF3, AF_ADJUST_DOWN }, /* ῳ */ + { 0x1FF4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῴ */ + { 0x1FF6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῶ */ + { 0x1FF7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ῷ */ + { 0x1FFC, AF_ADJUST_DOWN }, /* ῼ */ + + /* General Punctuation */ + { 0x203C, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ‼ */ + { 0x203D, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ‽ */ + + { 0x2047, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁇ */ + { 0x2048, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁈ */ + { 0x2049, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁉ */ + + /* Superscripts and Subscripts */ + { 0x2071, AF_ADJUST_UP }, /* ⁱ */ + + /* Currency Symbols */ + { 0x20AB, AF_ADJUST_DOWN }, /* ₫ */ + + { 0x20C0, AF_ADJUST_DOWN }, /* ⃀ */ + + /* Number Forms */ + { 0x2170, AF_ADJUST_UP }, /* ⅰ */ + { 0x2171, AF_ADJUST_UP }, /* ⅱ */ + { 0x2172, AF_ADJUST_UP }, /* ⅲ */ + { 0x2173, AF_ADJUST_UP }, /* ⅳ */ + { 0x2175, AF_ADJUST_UP }, /* ⅵ */ + { 0x2176, AF_ADJUST_UP }, /* ⅶ */ + { 0x2177, AF_ADJUST_UP }, /* ⅷ */ + { 0x2178, AF_ADJUST_UP }, /* ⅸ */ + { 0x217A, AF_ADJUST_UP }, /* ⅺ */ + { 0x217B, AF_ADJUST_UP }, /* ⅻ */ + + /* Latin Extended-C */ + { 0x2C64, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɽ */ + { 0x2C67, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱨ */ + { 0x2C68, AF_IGNORE_SMALL_BOTTOM } , /* ⱨ */ + { 0x2C69, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱪ */ + { 0x2C6A, AF_IGNORE_SMALL_BOTTOM } , /* ⱪ */ + { 0x2C6B, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱬ */ + { 0x2C6C, AF_IGNORE_SMALL_BOTTOM } , /* ⱬ */ + { 0x2C6E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɱ */ + + { 0x2C7C, AF_ADJUST_UP }, /* ⱼ */ + { 0x2C7E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ȿ */ + { 0x2C7F, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɀ */ + + /* Coptic */ + { 0x2CC2, AF_ADJUST_UP }, /* Ⳃ */ + { 0x2CC3, AF_ADJUST_UP }, /* ⳃ */ + + /* Supplemental Punctuation */ + { 0x2E18, AF_ADJUST_UP }, /* ⸘ */ + + { 0x2E2E, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⸮ */ + + /* Cyrillic Extended-B */ + { 0xA640, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꙁ */ + { 0xA641, AF_IGNORE_SMALL_BOTTOM } , /* ꙁ */ + { 0xA642, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꙃ */ + { 0xA643, AF_IGNORE_SMALL_BOTTOM } , /* ꙃ */ + + { 0xA680, AF_IGNORE_CAPITAL_TOP } , /* Ꚁ */ + { 0xA681, AF_IGNORE_SMALL_TOP } , /* ꚁ */ + { 0xA688, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚉ */ + { 0xA689, AF_IGNORE_SMALL_BOTTOM } , /* ꚉ */ + { 0xA68A, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚋ */ + { 0xA68B, AF_IGNORE_SMALL_BOTTOM } , /* ꚋ */ + { 0xA68E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚏ */ + { 0xA68F, AF_IGNORE_SMALL_BOTTOM } , /* ꚏ */ + + { 0xA690, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚑ */ + { 0xA691, AF_IGNORE_SMALL_BOTTOM } , /* ꚑ */ + { 0xA696, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚗ */ + { 0xA697, AF_IGNORE_SMALL_BOTTOM } , /* ꚗ */ + + /* Latin Extended-D */ + { 0xA726, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꜧ */ + { 0xA727, AF_IGNORE_SMALL_BOTTOM } , /* ꜧ */ + + { 0xA756, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꝗ */ + { 0xA758, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꝙ */ + + { 0xA771, AF_IGNORE_SMALL_BOTTOM } , /* ꝱ */ + { 0xA772, AF_IGNORE_SMALL_BOTTOM } , /* ꝲ */ + { 0xA773, AF_IGNORE_SMALL_BOTTOM } , /* ꝳ */ + { 0xA774, AF_IGNORE_SMALL_BOTTOM } , /* ꝴ */ + { 0xA776, AF_IGNORE_SMALL_BOTTOM } , /* ꝶ */ + + { 0xA790, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꞑ */ + { 0xA791, AF_IGNORE_SMALL_BOTTOM } , /* ꞑ */ + { 0xA794, AF_IGNORE_SMALL_BOTTOM } , /* ꞔ */ + { 0xA795, AF_IGNORE_SMALL_BOTTOM } , /* ꞕ */ + + { 0xA7C0, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ꟁ */ + { 0xA7C1, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ꟁ */ + { 0xA7C4, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꞔ */ + { 0xA7C5, AF_IGNORE_CAPITAL_BOTTOM } , /* Ʂ */ + { 0xA7C6, AF_IGNORE_CAPITAL_BOTTOM } , /* Ᶎ */ + { 0xA7CC, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ꟍ */ + { 0xA7CD, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ꟍ */ + + /* Latin Extended-E */ + { 0xAB3C, AF_IGNORE_SMALL_BOTTOM } , /* ꬼ */ + + { 0xAB46, AF_IGNORE_SMALL_BOTTOM } , /* ꭆ */ + + { 0xAB5C, AF_IGNORE_SMALL_BOTTOM } , /* ꭜ */ + + { 0xAB66, AF_IGNORE_SMALL_BOTTOM } , /* ꭦ */ + { 0xAB67, AF_IGNORE_SMALL_BOTTOM } , /* ꭧ */ + }; + + + FT_LOCAL_DEF( FT_UInt32 ) + af_adjustment_database_lookup( FT_UInt32 codepoint ) + { + /* Binary search for database entry */ + FT_Offset low = 0; + FT_Offset high = AF_ADJUSTMENT_DATABASE_LENGTH - 1; + + + while ( high >= low ) + { + FT_Offset mid = ( low + high ) / 2; + FT_UInt32 mid_codepoint = adjustment_database[mid].codepoint; + + + if ( mid_codepoint < codepoint ) + low = mid + 1; + else if ( mid_codepoint > codepoint ) + high = mid - 1; + else + return adjustment_database[mid].flags; + } + + return 0; + } + + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + static FT_Error + add_substitute( FT_Int glyph_idx, + size_t value, + FT_UInt32 codepoint, + FT_Hash reverse_map, + FT_Hash subst_map, + FT_Memory memory ) + { + FT_Error error; + + FT_Int first_substitute = (FT_Int)( value & 0xFFFF ); + + FT_UInt used = reverse_map->used; + + + /* + OpenType features like 'unic' map lowercase letter glyphs to uppercase + forms (and vice versa), which could lead to the use of wrong entries + in the adjustment database. For this reason we don't overwrite, + prioritizing cmap entries. + + XXX Note, however, that this cannot cover all cases since there might + be contradictory entries for glyphs not in the cmap. A possible + solution might be to specially mark pairs of related lowercase and + uppercase characters in the adjustment database that have diacritics + on different vertical sides (for example, U+0122 'Ģ' and U+0123 'ģ'). + The auto-hinter could then perform a topological analysis to do the + right thing. + */ + error = ft_hash_num_insert_no_overwrite( first_substitute, codepoint, + reverse_map, memory ); + if ( error ) + return error; + + if ( reverse_map->used > used ) + { + size_t* subst = ft_hash_num_lookup( first_substitute, subst_map ); + + + if ( subst ) + { + error = add_substitute( first_substitute, *subst, codepoint, + reverse_map, subst_map, memory ); + if ( error ) + return error; + } + } + + /* The remaining substitutes. */ + if ( value & 0xFFFF0000U ) + { + FT_UInt num_substitutes = value >> 16; + + FT_UInt i; + + + for ( i = 1; i <= num_substitutes; i++ ) + { + FT_Int idx = glyph_idx + (FT_Int)( i << 16 ); + size_t* substitute = ft_hash_num_lookup( idx, subst_map ); + + + used = reverse_map->used; + + error = ft_hash_num_insert_no_overwrite( *substitute, + codepoint, + reverse_map, + memory ); + if ( error ) + return error; + + if ( reverse_map->used > used ) + { + size_t* subst = ft_hash_num_lookup( *substitute, subst_map ); + + + if ( subst ) + { + error = add_substitute( *substitute, *subst, codepoint, + reverse_map, subst_map, memory ); + if ( error ) + return error; + } + } + } + } + + return FT_Err_Ok; + } + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + /* Construct a 'reverse cmap' (i.e., a mapping from glyph indices to */ + /* character codes) for all glyphs that an input code point could turn */ + /* into. */ + /* */ + /* If HarfBuzz support is not available, this is the direct inversion */ + /* of the cmap table, otherwise the mapping gets extended with data */ + /* from the 'GSUB' table. */ + FT_LOCAL_DEF( FT_Error ) + af_reverse_character_map_new( FT_Hash *map, + AF_StyleMetrics metrics ) + { + FT_Error error; + + AF_FaceGlobals globals = metrics->globals; + FT_Face face = globals->face; + FT_Memory memory = face->memory; + + FT_CharMap old_charmap; + + FT_UInt32 codepoint; + FT_Offset i; + + + FT_TRACE4(( "af_reverse_character_map_new:" + " building reverse character map (style `%s')\n", + af_style_names[metrics->style_class->style] )); + + /* Search for a unicode charmap. */ + /* If there isn't one, create a blank map. */ + + /* Back up `face->charmap` because `find_unicode_charmap` sets it. */ + old_charmap = face->charmap; + + if ( ( error = find_unicode_charmap( face ) ) ) + goto Exit; + + *map = NULL; + if ( FT_QNEW( *map ) ) + goto Exit; + + error = ft_hash_num_init( *map, memory ); + if ( error ) + goto Exit; + + /* Initialize reverse cmap with data directly from the cmap table. */ + for ( i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ ) + { + FT_Int cmap_glyph; + + + /* + We cannot restrict `codepoint` to character ranges; we have no + control what data the script-specific portion of the GSUB table + actually holds. + + An example is `arial.ttf` version 7.00; in this font, there are + lookups for Cyrillic (lookup 43), Greek (lookup 44), and Latin + (lookup 45) that map capital letter glyphs to small capital glyphs. + It is tempting to expect that script-specific versions of the 'c2sc' + feature only use script-specific lookups. However, this is not the + case in this font: the feature uses all three lookups regardless of + the script. + + The auto-hinter, while assigning glyphs to styles, uses the first + coverage result it encounters for a particular glyph. For example, + if the coverage for Cyrillic is tested before Latin (as is currently + the case), glyphs without a cmap entry that are covered in 'c2sc' + are treated as Cyrillic. + + If we now look at glyph 3498, which is a small-caps version of the + Latin character 'A grave' (U+00C0, glyph 172), we can see that it is + registered as belonging to a Cyrillic style due to the algorithm + just described. As a result, checking only for characters from the + Latin range would miss this glyph; we thus have to test all + character codes in the database. + */ + codepoint = adjustment_database[i].codepoint; + + cmap_glyph = (FT_Int)FT_Get_Char_Index( face, codepoint ); + if ( cmap_glyph == 0 ) + continue; + + error = ft_hash_num_insert( cmap_glyph, codepoint, *map, memory ); + if ( error ) + goto Exit; + } + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + if ( ft_hb_enabled( globals ) ) + { + hb_font_t *hb_font; + hb_face_t *hb_face; + + hb_set_t *gsub_lookups; + hb_script_t script; + + unsigned int script_count = 1; + hb_tag_t script_tags[2] = { HB_TAG_NONE, HB_TAG_NONE }; + + FT_Hash subst_map = NULL; + + hb_codepoint_t idx; + FT_UInt hash_idx; + FT_Int glyph_idx; + size_t value; + + + /* No need to check whether HarfBuzz has allocation issues; */ + /* it continues to work in such cases and simply returns */ + /* 'empty' objects that do nothing. */ + + hb_font = globals->hb_font; + hb_face = hb( font_get_face )( hb_font ); + + gsub_lookups = hb( set_create )(); + + script = af_hb_scripts[metrics->style_class->script]; + + hb( ot_tags_from_script_and_language )( script, NULL, + &script_count, script_tags, + NULL, NULL ); + + /* Compute set of all script-specific GSUB lookups. */ + hb( ot_layout_collect_lookups )( hb_face, + HB_OT_TAG_GSUB, + script_tags, NULL, NULL, + gsub_lookups ); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Bool have_idx = FALSE; + + + FT_TRACE4(( " GSUB lookups to check:\n" )); + + FT_TRACE4(( " " )); + idx = HB_SET_VALUE_INVALID; + while ( hb( set_next )( gsub_lookups, &idx ) ) + if ( globals->gsub_lookups_single_alternate[idx] ) + { + have_idx = TRUE; + FT_TRACE4(( " %u", idx )); + } + if ( !have_idx ) + FT_TRACE4(( " (none)" )); + FT_TRACE4(( "\n" )); + + FT_TRACE4(( "\n" )); + } +#endif + + if ( FT_QNEW( subst_map ) ) + goto Exit_HarfBuzz; + + error = ft_hash_num_init( subst_map, memory ); + if ( error ) + goto Exit_HarfBuzz; + + idx = HB_SET_VALUE_INVALID; + while ( hb( set_next )( gsub_lookups, &idx ) ) + { + FT_UInt32 offset = globals->gsub_lookups_single_alternate[idx]; + + + /* Put all substitutions into a single hash table. Note that */ + /* the hash values usually contain more than a single character */ + /* code; this can happen if different 'SingleSubst' subtables */ + /* map a given glyph index to different substitutions, or if */ + /* 'AlternateSubst' subtable entries are present. */ + if ( offset ) + af_map_lookup( globals, subst_map, offset ); + } + + /* + Now iterate over the collected substitution data in `subst_map` + (using recursion to resolve one-to-many mappings) and insert the + data into the reverse cmap. + + As an example, suppose we have the following cmap and substitution + data: + + cmap: X -> a + Y -> b + Z -> c + + substitutions: a -> b + b -> c, d + d -> e + + The reverse map now becomes as follows. + + a -> X + b -> Y + c -> Z (via cmap, ignoring mapping from 'b') + d -> Y (via 'b') + e -> Y (via 'b' and 'd') + */ + + hash_idx = 0; + while ( ft_hash_num_iterator( &hash_idx, + &glyph_idx, + &value, + subst_map ) ) + { + size_t* val; + + + /* Ignore keys that do not point to the first substitute. */ + if ( (FT_UInt)glyph_idx & 0xFFFF0000U ) + continue; + + /* Ignore glyph indices that are not related to accents. */ + val = ft_hash_num_lookup( glyph_idx, *map ); + if ( !val ) + continue; + + codepoint = *val; + + error = add_substitute( glyph_idx, value, codepoint, + *map, subst_map, memory ); + if ( error ) + break; + } + + Exit_HarfBuzz: + hb( set_destroy )( gsub_lookups ); + + ft_hash_num_free( subst_map, memory ); + FT_FREE( subst_map ); + + if ( error ) + goto Exit; + } + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + + FT_TRACE4(( " reverse character map built successfully" + " with %u entries\n", ( *map )->used )); + +#ifdef FT_DEBUG_LEVEL_TRACE + + { + FT_UInt cnt; + + + FT_TRACE7(( " gidx code flags\n" )); + /* " XXXXX 0xXXXX XXXXXXXXXXX..." */ + FT_TRACE7(( " ------------------------------\n" )); + + for ( cnt = 0; cnt < globals->glyph_count; cnt++ ) + { + size_t* val; + FT_UInt32 adj_type; + + const char* flag_names[] = + { + "up", /* AF_ADJUST_UP */ + "down", /* AF_ADJUST_DOWN */ + "double up", /* AF_ADJUST_UP2 */ + "double down", /* AF_ADJUST_DOWN2 */ + + "top tilde", /* AF_ADJUST_TILDE_TOP */ + "bottom tilde", /* AF_ADJUST_TILDE_BOTTOM */ + "below-top tilde", /* AF_ADJUST_TILDE_TOP2 */ + "above-bottom tilde", /* AF_ADJUST_TILDE_BOTTOM2 */ + + "ignore capital top", /* AF_IGNORE_CAPITAL_TOP */ + "ignore capital bottom", /* AF_IGNORE_CAPITAL_BOTTOM */ + "ignore small top", /* AF_IGNORE_SMALL_TOP */ + "ignore small bottom", /* AF_IGNORE_SMALL_BOTTOM */ + }; + size_t flag_names_size = sizeof ( flag_names ) / sizeof ( char* ); + + char flag_str[256]; + int need_comma; + + size_t j; + + + val = ft_hash_num_lookup( (FT_Int)cnt, *map ); + if ( !val ) + continue; + codepoint = *val; + + adj_type = af_adjustment_database_lookup( codepoint ); + if ( !adj_type ) + continue; + + flag_str[0] = '\0'; + need_comma = 0; + + for ( j = 0; j < flag_names_size; j++ ) + { + if ( adj_type & (1 << j ) ) + { + if ( !need_comma ) + need_comma = 1; + else + strcat( flag_str, ", " ); + strcat( flag_str, flag_names[j] ); + } + } + + FT_TRACE7(( " %5u 0x%04X %s\n", cnt, codepoint, flag_str )); + } + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + Exit: + face->charmap = old_charmap; + + if ( error ) + { + FT_TRACE4(( " error while building reverse character map." + " Using blank map.\n" )); + + if ( *map ) + ft_hash_num_free( *map, memory ); + + FT_FREE( *map ); + *map = NULL; + return error; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + af_reverse_character_map_done( FT_Hash map, + FT_Memory memory ) + { + if ( map ) + ft_hash_num_free( map, memory ); + FT_FREE( map ); + + return FT_Err_Ok; + } + + +/* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.h b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.h new file mode 100644 index 00000000000..4837451ae4c --- /dev/null +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afadjust.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * afadjust.h + * + * Auto-fitter routines to adjust components based on charcode (header). + * + * Copyright (C) 2023-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Craig White . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef AFADJUST_H_ +#define AFADJUST_H_ + +#include + +#include "afglobal.h" +#include "aftypes.h" + + +FT_BEGIN_HEADER + + /* + * Adjustment type flags. + * + * They also specify topological constraints that the auto-hinter relies + * on. For example, using `AF_ADJUST_UP` implies that we have two + * enclosing contours, one for the base glyph and one for the diacritic + * above, and no other contour inbetween or above. With 'enclosing' it is + * meant that such a contour can contain more inner contours. + * + */ + + /* Find the topmost contour and push it up until its lowest point is */ + /* one pixel above the highest point not enclosed by that contour. */ +#define AF_ADJUST_UP 0x01 + + /* Find the bottommost contour and push it down until its highest point */ + /* is one pixel below the lowest point not enclosed by that contour. */ +#define AF_ADJUST_DOWN 0x02 + + /* Find the contour below the topmost contour and push it up, together */ + /* with the topmost contour, until its lowest point is one pixel above */ + /* the highest point not enclosed by that contour. This flag is */ + /* mutually exclusive with `AF_ADJUST_UP`. */ +#define AF_ADJUST_UP2 0x04 + + /* Find the contour above the bottommost contour and push it down, */ + /* together with the bottommost contour, until its highest point is */ + /* one pixel below the lowest point not enclosed by that contour. */ + /* This flag is mutually exclusive with `AF_ADJUST_DOWN`. */ +#define AF_ADJUST_DOWN2 0x08 + + /* The topmost contour is a tilde. Enlarge it vertically so that it */ + /* stays legible at small sizes, not degenerating to a horizontal line. */ +#define AF_ADJUST_TILDE_TOP 0x10 + + /* The bottommost contour is a tilde. Enlarge it vertically so that it */ + /* stays legible at small sizes, not degenerating to a horizontal line. */ +#define AF_ADJUST_TILDE_BOTTOM 0x20 + + /* The contour below the topmost contour is a tilde. Enlarge it */ + /* vertically so that it stays legible at small sizes, not degenerating */ + /* to a horizontal line. To be used with `AF_ADJUST_UP2` only. */ +#define AF_ADJUST_TILDE_TOP2 0x40 + + /* The contour above the bottommost contour is a tilde. Enlarge it */ + /* vertically so that it stays legible at small sizes, not degenerating */ + /* to a horizontal line. To be used with `AF_ADJUST_DOWN2` only. */ +#define AF_ADJUST_TILDE_BOTTOM2 0x80 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the top */ + /* of an uppercase base character. */ +#define AF_IGNORE_CAPITAL_TOP 0x100 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the */ + /* bottom of an uppercase base character. */ +#define AF_IGNORE_CAPITAL_BOTTOM 0x200 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the top */ + /* of a lowercase base character. */ +#define AF_IGNORE_SMALL_TOP 0x400 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the */ + /* bottom of a lowercase base character. */ +#define AF_IGNORE_SMALL_BOTTOM 0x800 + + /* By default, the AF_ADJUST_XXX flags are applied only if diacritics */ + /* have a 'small' height (based on some heuristic checks). If this */ + /* flag is set, no such check is performed. */ +#define AF_ADJUST_NO_HEIGHT_CHECK 0x1000 + + /* No adjustment, i.e., no flag is set. */ +#define AF_ADJUST_NONE 0x00 + + + FT_LOCAL( FT_UInt32 ) + af_adjustment_database_lookup( FT_UInt32 codepoint ); + + /* Allocate and populate the reverse character map, */ + /* using the character map within the face. */ + FT_LOCAL( FT_Error ) + af_reverse_character_map_new( FT_Hash *map, + AF_StyleMetrics metrics ); + + /* Free the reverse character map. */ + FT_LOCAL( FT_Error ) + af_reverse_character_map_done( FT_Hash map, + FT_Memory memory ); + + +FT_END_HEADER + +#endif /* AFADJUST_H_ */ + + +/* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c index ea83969cdc9..a6219bdfe41 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.c @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -467,24 +467,24 @@ af_blue_stringsets[] = { /* */ - { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_ARABIC_BOTTOM, 0 }, { AF_BLUE_STRING_ARABIC_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_AVESTAN_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -508,14 +508,14 @@ { AF_BLUE_STRING_CHAKMA_BOTTOM, 0 }, { AF_BLUE_STRING_CHAKMA_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 }, { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_CARIAN_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -527,24 +527,24 @@ { AF_BLUE_STRING_CHEROKEE_SMALL, 0 }, { AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_CYPRIOT_BOTTOM, 0 }, { AF_BLUE_STRING_CYPRIOT_SMALL, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_CYPRIOT_SMALL, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, - { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_DEVANAGARI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_DEVANAGARI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | @@ -553,12 +553,12 @@ { AF_BLUE_STRING_DEVANAGARI_BASE, 0 }, { AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -578,23 +578,23 @@ { AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GOTHIC_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_GREEK_SMALL, 0 }, - { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GREEK_SMALL, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_GUJARATI_BOTTOM, 0 }, @@ -643,45 +643,45 @@ { AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LAO_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 }, - { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 }, - { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LISU_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_MALAYALAM_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -691,12 +691,12 @@ { AF_BLUE_STRING_MYANMAR_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_MYANMAR_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_NKO_BOTTOM, 0 }, + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_NKO_BOTTOM, 0 }, { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_OL_CHIKI, 0 }, @@ -704,15 +704,15 @@ { AF_BLUE_STRING_OLD_TURKIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 }, - { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 }, + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_OSMANYA_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -723,13 +723,13 @@ { AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 }, - { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 }, + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 }, + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 }, { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_SINHALA_BOTTOM, 0 }, { AF_BLUE_STRING_SINHALA_DESCENDER, 0 }, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin index d2270fac744..786c6b3b9e6 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.cin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat index 88bab2632ab..f6e96ff8189 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.dat @@ -2,7 +2,7 @@ // // Auto-fitter data for blue strings. // -// Copyright (C) 2013-2024 by +// Copyright (C) 2013-2025 by // David Turner, Robert Wilhelm, and Werner Lemberg. // // This file is part of the FreeType project, and may only be used, @@ -699,12 +699,12 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: AF_BLUE_STRINGSET_ADLM - { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_ARAB { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -713,14 +713,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_ARMN - { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_AVST { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -756,14 +756,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CANS - { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 } { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CARI { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -781,12 +781,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_COPT - { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CPRT { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -796,13 +796,13 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CYRL - { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_CYRILLIC_SMALL, 0 } - { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_DEVA { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -815,12 +815,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_DSRT - { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_ETHI { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -848,12 +848,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GLAG - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GOTH { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -861,14 +861,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GREK - { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_GREEK_SMALL, 0 } - { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GREEK_SMALL, 0 } + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GUJR { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | @@ -935,34 +935,34 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LATN - { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LATB - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 } - { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LATP - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 } - { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LISU { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -975,15 +975,15 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_MEDF - { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_MONG { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP } @@ -999,12 +999,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_NKOO - { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_NKO_BOTTOM, 0 } + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_NKO_BOTTOM, 0 } { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_NONE { AF_BLUE_STRING_MAX, 0 } @@ -1020,15 +1020,15 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_OSGE - { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 } - { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 } + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_OSMA { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -1047,13 +1047,13 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_SHAW - { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 } - { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 } + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 } + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 } { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_SINH { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h index 2aa9d0984ef..5bb8406dc2b 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.h @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -314,14 +314,17 @@ FT_BEGIN_HEADER /* Properties are specific to a writing system. We assume that a given */ /* blue string can't be used in more than a single writing system, which */ /* is a safe bet. */ -#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must be value 1 */ #define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) #define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) #define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) #define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) -#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ -#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM ( 1U << 5 ) +#define AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM ( 1U << 6 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must be value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must be value 2 */ #define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin index 38031505a85..dbac14548d5 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afblue.hin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -99,14 +99,17 @@ FT_BEGIN_HEADER /* Properties are specific to a writing system. We assume that a given */ /* blue string can't be used in more than a single writing system, which */ /* is a safe bet. */ -#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must be value 1 */ #define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) #define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) #define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) #define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) -#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ -#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM ( 1U << 5 ) +#define AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM ( 1U << 6 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must be value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must be value 2 */ #define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c index 869b60487c2..7086601838c 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (body). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -90,12 +90,8 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif const char* p; @@ -105,9 +101,8 @@ p = script_class->standard_charstring; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); /* We check a list of standard characters. The first match wins. */ @@ -144,7 +139,7 @@ break; } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); if ( !glyph_index ) goto Exit; @@ -152,7 +147,7 @@ if ( !glyph_index ) goto Exit; - FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n", + FT_TRACE5(( "standard character: U+%04lX (glyph index %lu)\n", ch, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); @@ -297,12 +292,8 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* we walk over the blue character strings as specified in the */ @@ -313,9 +304,8 @@ FT_TRACE5(( "==========================\n" )); FT_TRACE5(( "\n" )); -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { @@ -340,7 +330,7 @@ }; - FT_TRACE5(( "blue zone %d (%s):\n", + FT_TRACE5(( "blue zone %u (%s):\n", axis->blue_count, cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) | AF_CJK_IS_TOP_BLUE( bs ) ] )); @@ -553,7 +543,7 @@ } /* end for loop */ - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); FT_TRACE5(( "\n" )); @@ -572,23 +562,20 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* in all supported charmaps, digits have character codes 0x30-0x39 */ const char digits[] = "0 1 2 3 4 5 6 7 8 9"; const char* p; + FT_UNUSED( face ); + p = digits; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); while ( *p ) { @@ -624,7 +611,7 @@ } } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); metrics->root.digits_have_same_width = same_width; } @@ -710,7 +697,7 @@ FT_Pos delta1, delta2; - blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); /* shoot is under shoot for cjk */ delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org; @@ -736,7 +723,7 @@ blue->shoot.fit = blue->ref.fit - delta2; - FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n", + FT_TRACE5(( ">> active cjk blue zone %c%u[%ld/%ld]:\n", ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', nn, blue->ref.org, blue->shoot.org )); FT_TRACE5(( " ref: cur=%.2f fit=%.2f\n", @@ -1378,7 +1365,7 @@ } - /* Initalize hinting engine. */ + /* Initialize hinting engine. */ FT_LOCAL_DEF( FT_Error ) af_cjk_hints_init( AF_GlyphHints hints, @@ -2185,7 +2172,7 @@ af_cjk_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) { - AF_AxisHints axis = & hints->axis[dim]; + AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); AF_Edge edge; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h index bc5aaf12e6e..bd1b39358e0 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcjk.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (specification). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h b/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h index 7980cf2e979..b93bcd1a2c5 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afcover.h @@ -4,7 +4,7 @@ * * Auto-fitter coverages (specification only). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c index ad667d2edc7..8613544f913 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.c @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (body). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h index 613c2f88a38..78a79439d95 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afdummy.h @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h b/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h index ae584ff06db..f3093fc90df 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aferrors.h @@ -4,7 +4,7 @@ * * Autofitter error codes (specification only). * - * Copyright (C) 2005-2024 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c index b7403fa65e1..e74d8141161 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.c @@ -4,7 +4,7 @@ * * Auto-fitter routines to compute global hinting values (body). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,6 +22,11 @@ #include "afws-decl.h" #include +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ +# include "afgsub.h" +# include "ft-hb-ft.h" +#endif + /************************************************************************** * @@ -184,7 +189,7 @@ if ( gindex != 0 && gindex < globals->glyph_count && ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) - gstyles[gindex] = ss; + gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY; for (;;) { @@ -195,7 +200,7 @@ if ( gindex < globals->glyph_count && ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) - gstyles[gindex] = ss; + gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY; } } @@ -301,7 +306,7 @@ if ( !( count % 10 ) ) FT_TRACE4(( " " )); - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; if ( !( count % 10 ) ) @@ -356,8 +361,21 @@ globals->scale_down_factor = 0; #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - globals->hb_font = hb_ft_font_create_( face, NULL ); - globals->hb_buf = hb_buffer_create(); + if ( ft_hb_enabled ( globals ) ) + { + globals->hb_font = ft_hb_ft_font_create( globals ); + globals->hb_buf = hb( buffer_create )(); + + af_parse_gsub( globals ); + } + else + { + globals->hb_font = NULL; + globals->hb_buf = NULL; + + globals->gsub = NULL; + globals->gsub_lookups_single_alternate = NULL; + } #endif error = af_face_globals_compute_style_coverage( globals ); @@ -405,8 +423,14 @@ } #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - hb_font_destroy( globals->hb_font ); - hb_buffer_destroy( globals->hb_buf ); + if ( ft_hb_enabled ( globals ) ) + { + hb( font_destroy )( globals->hb_font ); + hb( buffer_destroy )( globals->hb_buf ); + + FT_FREE( globals->gsub ); + FT_FREE( globals->gsub_lookups_single_alternate ); + } #endif /* no need to free `globals->glyph_styles'; */ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h index ddb54c89b27..362f56e290b 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afglobal.h @@ -5,7 +5,7 @@ * Auto-fitter routines to compute global hinting values * (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -73,15 +73,17 @@ FT_BEGIN_HEADER /* default script for OpenType; ignored if HarfBuzz isn't used */ #define AF_SCRIPT_DEFAULT AF_SCRIPT_LATN - /* a bit mask for AF_DIGIT and AF_NONBASE */ -#define AF_STYLE_MASK 0x3FFF + /* a bit mask for AF_DIGIT, AF_NONBASE, and AF_HAS_CMAP_ENTRY */ +#define AF_STYLE_MASK 0x1FFF /* an uncovered glyph */ #define AF_STYLE_UNASSIGNED AF_STYLE_MASK - /* if this flag is set, we have an ASCII digit */ + /* if this flag is set, we have an ASCII digit */ #define AF_DIGIT 0x8000U /* if this flag is set, we have a non-base character */ #define AF_NONBASE 0x4000U + /* if this flag is set, the glyph has a (direct) cmap entry */ +#define AF_HAS_CMAP_ENTRY 0x2000U /* `increase-x-height' property */ #define AF_PROP_INCREASE_X_HEIGHT_MIN 6 @@ -111,6 +113,11 @@ FT_BEGIN_HEADER #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ hb_font_t* hb_font; hb_buffer_t* hb_buf; /* for feature comparison */ + + /* The GSUB table. */ + FT_Byte* gsub; + /* Lookup offsets, with only SingleSubst and AlternateSubst non-NULL. */ + FT_UInt32* gsub_lookups_single_alternate; #endif /* per-face auto-hinter properties */ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c index 96ffe343aa4..11faa655f62 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (body). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -840,6 +840,10 @@ if ( hints->contours != hints->embedded.contours ) FT_FREE( hints->contours ); + if ( hints->contour_y_minima != hints->embedded.contour_y_minima ) + FT_FREE( hints->contour_y_minima ); + if ( hints->contour_y_maxima != hints->embedded.contour_y_maxima ) + FT_FREE( hints->contour_y_maxima ); hints->max_contours = 0; hints->num_contours = 0; @@ -896,19 +900,30 @@ { if ( !hints->contours ) { - hints->contours = hints->embedded.contours; + hints->contours = hints->embedded.contours; + hints->contour_y_minima = hints->embedded.contour_y_minima; + hints->contour_y_maxima = hints->embedded.contour_y_maxima; + hints->max_contours = AF_CONTOURS_EMBEDDED; } } else if ( new_max > old_max ) { if ( hints->contours == hints->embedded.contours ) - hints->contours = NULL; + { + hints->contours = NULL; + hints->contour_y_minima = NULL; + hints->contour_y_maxima = NULL; + } new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) goto Exit; + if ( FT_RENEW_ARRAY( hints->contour_y_minima, old_max, new_max ) ) + goto Exit; + if ( FT_RENEW_ARRAY( hints->contour_y_maxima, old_max, new_max ) ) + goto Exit; hints->max_contours = new_max; } @@ -1324,7 +1339,7 @@ af_glyph_hints_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) { - AF_AxisHints axis = & hints->axis[dim]; + AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Segment seg; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h index 76fe83006a5..46b3ed3366f 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afhints.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -222,6 +222,9 @@ FT_BEGIN_HEADER /* the distance to the next point is very small */ #define AF_FLAG_NEAR ( 1U << 5 ) + /* prevent the auto-hinter from adding such a point to a segment */ +#define AF_FLAG_IGNORE ( 1U << 6 ) + /* edge hint flags */ #define AF_EDGE_NORMAL 0 @@ -229,6 +232,7 @@ FT_BEGIN_HEADER #define AF_EDGE_SERIF ( 1U << 1 ) #define AF_EDGE_DONE ( 1U << 2 ) #define AF_EDGE_NEUTRAL ( 1U << 3 ) /* edge aligns to a neutral blue zone */ +#define AF_EDGE_NO_BLUE ( 1U << 4 ) /* do not align edge to blue zone */ typedef struct AF_PointRec_* AF_Point; @@ -303,6 +307,7 @@ FT_BEGIN_HEADER } AF_EdgeRec; + #define AF_SEGMENTS_EMBEDDED 18 /* number of embedded segments */ #define AF_EDGES_EMBEDDED 12 /* number of embedded edges */ @@ -346,9 +351,11 @@ FT_BEGIN_HEADER FT_Int num_points; /* number of used points */ AF_Point points; /* points array */ - FT_Int max_contours; /* number of allocated contours */ - FT_Int num_contours; /* number of used contours */ - AF_Point* contours; /* contours array */ + FT_Int max_contours; /* number of allocated contours */ + FT_Int num_contours; /* number of used contours */ + AF_Point* contours; /* contours array */ + FT_Pos* contour_y_minima; /* array with y maxima of contours */ + FT_Pos* contour_y_maxima; /* array with y minima of contours */ AF_AxisHintsRec axis[AF_DIMENSION_MAX]; @@ -357,11 +364,13 @@ FT_BEGIN_HEADER /* implementations */ AF_StyleMetrics metrics; - /* Two arrays to avoid allocation penalty. */ + /* Some arrays to avoid allocation penalty. */ /* The `embedded' structure must be the last element! */ struct { AF_Point contours[AF_CONTOURS_EMBEDDED]; + FT_Pos contour_y_minima[AF_CONTOURS_EMBEDDED]; + FT_Pos contour_y_maxima[AF_CONTOURS_EMBEDDED]; AF_PointRec points[AF_POINTS_EMBEDDED]; } embedded; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c index c6d23efd86f..a2cd14f8817 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for Indic writing system (body). * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h index a7f73f25153..a2e825e9f86 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afindic.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for Indic writing system * (specification). * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c index 89287f7ea5a..cb5667ff793 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for latin writing system (body). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,6 +22,7 @@ #include "afglobal.h" #include "aflatin.h" #include "aferrors.h" +#include "afadjust.h" /************************************************************************** @@ -81,12 +82,8 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif const char* p; @@ -97,9 +94,9 @@ p = script_class->standard_charstring; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled ( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); + /* * We check a list of standard characters to catch features like * `c2sc' (small caps from caps) that don't contain lowercase letters @@ -140,7 +137,7 @@ break; } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); if ( !glyph_index ) { @@ -149,7 +146,7 @@ goto Exit; } - FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n", + FT_TRACE5(( "standard character: U+%04lX (glyph index %lu)\n", ch, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); @@ -334,12 +331,8 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* we walk over the blue character strings as specified in the */ @@ -349,9 +342,8 @@ FT_TRACE5(( "============================\n" )); FT_TRACE5(( "\n" )); -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled ( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { @@ -367,7 +359,7 @@ FT_Bool have_flag = 0; - FT_TRACE5(( "blue zone %d", axis->blue_count )); + FT_TRACE5(( "blue zone %u", axis->blue_count )); if ( bs->properties ) { @@ -407,6 +399,20 @@ FT_TRACE5(( "long" )); } + if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "capital bottom" )); + } + + if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "small bottom" )); + } + FT_TRACE5(( ")" )); } @@ -454,9 +460,9 @@ } if ( AF_LATIN_IS_TOP_BLUE( bs ) ) - best_y_extremum = FT_INT_MIN; + best_y_extremum = FT_LONG_MIN; else - best_y_extremum = FT_INT_MAX; + best_y_extremum = FT_LONG_MAX; /* iterate over all glyph elements of the character cluster */ /* and get the data of the `biggest' one */ @@ -487,7 +493,7 @@ if ( num_idx == 1 ) FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); else - FT_TRACE5(( " component %d of cluster starting with U+%04lX" + FT_TRACE5(( " component %u of cluster starting with U+%04lX" " contains no (usable) outlines\n", i, ch )); #endif continue; @@ -825,7 +831,7 @@ if ( num_idx == 1 ) FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y )); else - FT_TRACE5(( " component %d of cluster starting with U+%04lX:" + FT_TRACE5(( " component %u of cluster starting with U+%04lX:" " best_y = %5ld", i, ch, best_y )); #endif @@ -879,8 +885,8 @@ } /* end for loop */ - if ( !( best_y_extremum == FT_INT_MIN || - best_y_extremum == FT_INT_MAX ) ) + if ( !( best_y_extremum == FT_LONG_MIN || + best_y_extremum == FT_LONG_MAX ) ) { if ( best_round ) rounds[num_rounds++] = best_y_extremum; @@ -959,6 +965,10 @@ blue->flags |= AF_LATIN_BLUE_SUB_TOP; if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_NEUTRAL; + if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_BOTTOM; + if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_BOTTOM_SMALL; /* * The following flag is used later to adjust the y and x scales @@ -973,7 +983,7 @@ } /* end for loop */ - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); if ( axis->blue_count ) { @@ -1070,23 +1080,20 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* in all supported charmaps, digits have character codes 0x30-0x39 */ const char digits[] = "0 1 2 3 4 5 6 7 8 9"; const char* p; + FT_UNUSED( face ); + p = digits; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled ( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); while ( *p ) { @@ -1122,7 +1129,7 @@ } } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); metrics->root.digits_have_same_width = same_width; } @@ -1155,6 +1162,9 @@ af_latin_metrics_check_digits( metrics, face ); } + af_reverse_character_map_new( &metrics->root.reverse_charmap, + &metrics->root ); + Exit: face->charmap = oldmap; return error; @@ -1263,7 +1273,7 @@ max_height = FT_MAX( max_height, -Axis->blues[nn].descender ); } - dist = FT_MulFix( max_height, new_scale - scale ); + dist = FT_MulFix( max_height, new_scale - scale ); if ( -128 < dist && dist < 128 ) { @@ -1466,13 +1476,13 @@ AF_LatinBlue blue = &axis->blues[nn]; - FT_TRACE5(( " reference %d: %ld scaled to %.2f%s\n", + FT_TRACE5(( " reference %u: %ld scaled to %.2f%s\n", nn, blue->ref.org, (double)blue->ref.fit / 64, ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" : " (inactive)" )); - FT_TRACE5(( " overshoot %d: %ld scaled to %.2f%s\n", + FT_TRACE5(( " overshoot %u: %ld scaled to %.2f%s\n", nn, blue->shoot.org, (double)blue->shoot.fit / 64, @@ -1484,6 +1494,17 @@ } + FT_CALLBACK_DEF( void ) + af_latin_metrics_done( AF_StyleMetrics metrics_ ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + + af_reverse_character_map_done( metrics->root.reverse_charmap, + metrics->root.globals->face->memory ); + } + + /* Scale global values in both directions. */ FT_LOCAL_DEF( void ) @@ -1617,7 +1638,8 @@ FT_Pos prev_max_on_coord = max_on_coord; - if ( FT_ABS( last->out_dir ) == major_dir && + if ( !( point->flags & AF_FLAG_IGNORE ) && + FT_ABS( last->out_dir ) == major_dir && FT_ABS( point->out_dir ) == major_dir ) { /* we are already on an edge, try to locate its start */ @@ -1676,13 +1698,17 @@ max_on_coord = v; } - if ( point->out_dir != segment_dir || point == last ) + if ( point->flags & AF_FLAG_IGNORE || + point->out_dir != segment_dir || + point == last ) { /* check whether the new segment's start point is identical to */ /* the previous segment's end point; for example, this might */ /* happen for spikes */ - if ( !prev_segment || segment->first != prev_segment->last ) + if ( point->flags & AF_FLAG_IGNORE || + !prev_segment || + segment->first != prev_segment->last ) { /* points are different: we are just leaving an edge, thus */ /* record a new segment */ @@ -1842,7 +1868,8 @@ /* if we are not on an edge, check whether the major direction */ /* coincides with the current point's `out' direction, or */ /* whether we have a single-point contour */ - if ( !on_edge && + if ( !( point->flags & AF_FLAG_IGNORE ) && + !on_edge && ( FT_ABS( point->out_dir ) == major_dir || point == point->prev ) ) { @@ -2521,6 +2548,9 @@ FT_Pos best_dist; /* initial threshold */ + if ( edge->flags & AF_EDGE_NO_BLUE ) + continue; + /* compute the initial threshold as a fraction of the EM size */ /* (the value 40 is heuristic) */ best_dist = FT_MulFix( metrics->units_per_em / 40, scale ); @@ -2610,7 +2640,7 @@ } - /* Initalize hinting engine. */ + /* Initialize hinting engine. */ static FT_Error af_latin_hints_init( AF_GlyphHints hints, @@ -2737,6 +2767,1192 @@ } +#undef FT_COMPONENT +#define FT_COMPONENT afadjust + + + static void + af_move_contour_vertically( AF_Point contour, + FT_Int movement ) + { + AF_Point point = contour; + AF_Point first_point = point; + + + if ( point ) + { + do + { + point->y += movement; + point = point->next; + + } while ( point != first_point ); + } + } + + + /* Move all contours higher than `limit` by `delta`. */ + static void + af_move_contours_up( AF_GlyphHints hints, + FT_Pos limit, + FT_Pos delta ) + { + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + min_y > limit ) + af_move_contour_vertically( hints->contours[contour], + delta ); + } + } + + + static void + af_move_contours_down( AF_GlyphHints hints, + FT_Pos limit, + FT_Pos delta ) + { + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + max_y < limit ) + af_move_contour_vertically( hints->contours[contour], + -delta ); + } + } + + + /* Compute vertical extrema of all contours and store them in the */ + /* `contour_y_minima` and `contour_y_maxima` arrays of `hints`. */ + static void + af_compute_vertical_extrema( AF_GlyphHints hints ) + { + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = FT_LONG_MAX; + FT_Pos max_y = FT_LONG_MIN; + + AF_Point first_point = hints->contours[contour]; + AF_Point point = first_point; + + + if ( !first_point || first_point->next->next == first_point ) + goto End_loop; + + do + { + if ( point->y < min_y ) + min_y = point->y; + if ( point->y > max_y ) + max_y = point->y; + + point = point->next; + + } while ( point != first_point ); + + End_loop: + hints->contour_y_minima[contour] = min_y; + hints->contour_y_maxima[contour] = max_y; + } + } + + + static FT_Int + af_find_highest_contour( AF_GlyphHints hints ) + { + FT_Int highest_contour = 0; + FT_Pos highest_min_y = FT_LONG_MAX; + FT_Pos highest_max_y = FT_LONG_MIN; + + FT_Int contour; + + + /* At this point we have one 'lower' (usually the base glyph) */ + /* and one 'upper' object (usually the diacritic glyph). If */ + /* there are more contours, they must be enclosed within either */ + /* 'lower' or 'upper'. To find this enclosing 'upper' contour */ + /* it is thus sufficient to search for the contour with the */ + /* highest y maximum value. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y = hints->contour_y_minima[contour]; + FT_Pos current_max_y = hints->contour_y_maxima[contour]; + + + /* If we have two contours with the same maximum value, take */ + /* the one that has a smaller height. */ + if ( current_max_y > highest_max_y || + ( current_max_y == highest_max_y && + current_min_y > highest_min_y ) ) + { + highest_min_y = current_min_y; + highest_max_y = current_max_y; + highest_contour = contour; + } + } + + return highest_contour; + } + + + static FT_Int + af_find_second_highest_contour( AF_GlyphHints hints ) + { + FT_Int highest_contour; + FT_Pos highest_min_y; + + FT_Int second_highest_contour = 0; + FT_Pos second_highest_max_y = FT_LONG_MIN; + + FT_Int contour; + + + if ( hints->num_contours < 3 ) + return 0; + + highest_contour = af_find_highest_contour( hints ); + highest_min_y = hints->contour_y_minima[highest_contour]; + + /* Search the contour with the largest vertical maximum that has a */ + /* vertical minimum lower than the vertical minimum of the topmost */ + /* contour. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y; + FT_Pos current_max_y; + + + if ( contour == highest_contour ) + continue; + + current_min_y = hints->contour_y_minima[contour]; + current_max_y = hints->contour_y_maxima[contour]; + + if ( current_max_y > second_highest_max_y && + current_min_y < highest_min_y ) + { + second_highest_max_y = current_max_y; + second_highest_contour = contour; + } + } + + return second_highest_contour; + } + + + static FT_Int + af_find_lowest_contour( AF_GlyphHints hints ) + { + FT_Int lowest_contour = 0; + FT_Pos lowest_min_y = FT_LONG_MAX; + FT_Pos lowest_max_y = FT_LONG_MIN; + + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y = hints->contour_y_minima[contour]; + FT_Pos current_max_y = hints->contour_y_maxima[contour]; + + + if ( current_min_y < lowest_min_y || + ( current_min_y == lowest_min_y && + current_max_y < lowest_max_y ) ) + { + lowest_min_y = current_min_y; + lowest_max_y = current_max_y; + lowest_contour = contour; + } + } + + return lowest_contour; + } + + + static FT_Int + af_find_second_lowest_contour( AF_GlyphHints hints ) + { + FT_Int lowest_contour; + FT_Pos lowest_max_y; + + FT_Int second_lowest_contour = 0; + FT_Pos second_lowest_min_y = FT_LONG_MAX; + + FT_Int contour; + + + if ( hints->num_contours < 3 ) + return 0; + + lowest_contour = af_find_lowest_contour( hints ); + lowest_max_y = hints->contour_y_maxima[lowest_contour]; + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y; + FT_Pos current_max_y; + + + if ( contour == lowest_contour ) + continue; + + current_min_y = hints->contour_y_minima[contour]; + current_max_y = hints->contour_y_maxima[contour]; + + if ( current_min_y < second_lowest_min_y && + current_max_y > lowest_max_y ) + { + second_lowest_min_y = current_min_y; + second_lowest_contour = contour; + } + } + + return second_lowest_contour; + } + + + /* While aligning edges to blue zones, make the auto-hinter */ + /* ignore the ones that are higher than `pos`. */ + static void + af_prevent_top_blue_alignment( AF_GlyphHints hints, + FT_Pos pos ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + if ( edge->pos > pos ) + edge->flags |= AF_EDGE_NO_BLUE; + } + + + static void + af_prevent_bottom_blue_alignment( AF_GlyphHints hints, + FT_Pos pos ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + if ( edge->pos < pos ) + edge->flags |= AF_EDGE_NO_BLUE; + } + + + static void + af_latin_get_base_glyph_blues( AF_GlyphHints hints, + FT_Bool is_capital, + AF_LatinBlue* top, + AF_LatinBlue* bottom ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; + AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; + + FT_UInt top_flag; + FT_UInt bottom_flag; + + FT_UInt i; + + + top_flag = is_capital ? AF_LATIN_BLUE_TOP + : AF_LATIN_BLUE_ADJUSTMENT; + top_flag |= AF_LATIN_BLUE_ACTIVE; + + for ( i = 0; i < axis->blue_count; i++ ) + if ( ( axis->blues[i].flags & top_flag ) == top_flag ) + break; + if ( i < axis->blue_count ) + *top = &axis->blues[i]; + + bottom_flag = is_capital ? AF_LATIN_BLUE_BOTTOM + : AF_LATIN_BLUE_BOTTOM_SMALL; + bottom_flag |= AF_LATIN_BLUE_ACTIVE; + + for ( i = 0; i < axis->blue_count; i++ ) + if ( ( axis->blues[i].flags & bottom_flag ) == bottom_flag ) + break; + if ( i < axis->blue_count ) + *bottom = &axis->blues[i]; + } + + + /* Make the auto-hinter ignore top blue zones while aligning edges. */ + /* This affects everything that is higher than a vertical position */ + /* based on the lowercase or uppercase top and bottom blue zones */ + /* (depending on `is_capital`). */ + static void + af_latin_ignore_top( AF_GlyphHints hints, + AF_LatinBlue top_blue, + AF_LatinBlue bottom_blue ) + { + FT_Pos base_glyph_height; + FT_Pos limit; + + + /* Ignore blue zones that are higher than a heuristic threshold */ + /* (value 7 corresponds to approx. 14%, which should be sufficient */ + /* to exceed the height of uppercase serifs. We also add a quarter */ + /* of a pixel as a safety measure. */ + base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur; + limit = top_blue->shoot.cur + base_glyph_height / 7 + 16; + + af_prevent_top_blue_alignment( hints, limit ); + } + + + static void + af_latin_ignore_bottom( AF_GlyphHints hints, + AF_LatinBlue top_blue, + AF_LatinBlue bottom_blue ) + { + FT_Pos base_glyph_height; + FT_Pos limit; + + + base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur; + limit = bottom_blue->shoot.cur - base_glyph_height / 7 - 16; + + af_prevent_bottom_blue_alignment( hints, limit ); + } + + + static void + af_touch_contour( AF_GlyphHints hints, + FT_Int contour ) + { + AF_Point first_point = hints->contours[contour]; + AF_Point p = first_point; + + + do + { + p = p->next; + + p->flags |= AF_FLAG_IGNORE; + if ( !( p->flags & AF_FLAG_CONTROL ) ) + p->flags |= AF_FLAG_TOUCH_Y; + + } while ( p != first_point ); + } + + + static void + af_touch_top_contours( AF_GlyphHints hints, + FT_Int limit_contour ) + { + FT_Pos limit = hints->contour_y_minima[limit_contour]; + + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + min_y >= limit ) + af_touch_contour( hints, contour ); + } + } + + + static void + af_touch_bottom_contours( AF_GlyphHints hints, + FT_Int limit_contour ) + { + FT_Pos limit = hints->contour_y_minima[limit_contour]; + + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + max_y <= limit ) + af_touch_contour( hints, contour ); + } + } + + + /* Stretch tilde vertically, if necessary, and return the height */ + /* difference between the original and the stretched outline. */ + static FT_Pos + af_latin_stretch_top_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = hints->contour_y_minima[tilde_contour]; + FT_Pos max_y = hints->contour_y_maxima[tilde_contour]; + + FT_Pos min_measurement = FT_LONG_MAX; + FT_Bool measurement_taken = FALSE; + + FT_Pos height; + FT_Pos extremum_threshold; + FT_Pos target_height; + + + if ( min_y == max_y ) + return 0; + + FT_TRACE4(( "af_latin_stretch_top_tilde: min y: %ld, max y: %ld\n", + min_y, max_y )); + + height = SUB_LONG( max_y, min_y ); + extremum_threshold = height / 8; /* Value 8 is heuristic. */ + + /* Find points that are local vertical round extrema, and which */ + /* do not coincide with the vertical extreme values (i.e., we */ + /* search for the 'other' wiggles in the tilde), then measure the */ + /* distance to the vertical extreme values. Try to find the one */ + /* with the smallest distance. */ + /* */ + /* The algorithm only works for tilde shapes that don't deviate */ + /* from the standard shape too much. In particular, the wiggles */ + /* must be round extrema. */ + do + { + p = p->next; + + if ( !( p->flags & AF_FLAG_CONTROL ) && + p->prev->y == p->y && p->next->y == p->y && + p->y != min_y && p->y != max_y && + p->prev->flags & AF_FLAG_CONTROL && + p->next->flags & AF_FLAG_CONTROL ) + { + /* This point could be a candidate. Find the next and previous */ + /* on-curve points, and make sure they are both either above or */ + /* below the point, then make the measurement. */ + AF_Point prev_on = p->prev; + AF_Point next_on = p->next; + + FT_Pos measurement; + + + while ( prev_on->flags & AF_FLAG_CONTROL ) + prev_on = prev_on->prev; + while ( next_on->flags & AF_FLAG_CONTROL ) + next_on = next_on->next; + + if ( next_on->y > p->y && prev_on->y > p->y ) + measurement = p->y - min_y; + else if ( next_on->y < p->y && prev_on->y < p->y ) + measurement = max_y - p->y; + else + continue; + + /* Ignore hits that are too near to a vertical extremum. */ + if ( measurement < extremum_threshold ) + continue; + + if ( !measurement_taken || measurement < min_measurement ) + { + measurement_taken = TRUE; + min_measurement = measurement; + } + } + + } while ( p != first_point ); + + if ( !measurement_taken ) + min_measurement = 0; + + FT_TRACE4(( "af_latin_stretch_top_tilde: min measurement %ld\n", + min_measurement )); + + /* To preserve the stretched shape we prevent that the tilde */ + /* gets auto-hinted; we do this for all contours equal or */ + /* above the vertical minimum of `tilde_contour`. */ + af_touch_top_contours( hints, tilde_contour ); + + /* XXX This is an important element of the algorithm; */ + /* we need a description. */ + target_height = min_measurement + 64; + if ( height >= target_height ) + return 0; + + /* Do the scaling. */ + p = first_point; + do + { + p = p->next; + /* We adjust the height of the diacritic only, which means */ + /* we are never dealing with large numbers and can thus avoid */ + /* `FT_MulFix`. */ + p->y = ( ( p->y - min_y ) * target_height / height ) + min_y; + + } while ( p != first_point ); + + return target_height - height; + } + + + static FT_Pos + af_latin_stretch_bottom_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = hints->contour_y_minima[tilde_contour]; + FT_Pos max_y = hints->contour_y_maxima[tilde_contour]; + + FT_Pos min_measurement = FT_LONG_MAX; + FT_Bool measurement_taken = FALSE; + + FT_Pos height; + FT_Pos extremum_threshold; + FT_Pos target_height; + + + if ( min_y == max_y ) + return 0; + + FT_TRACE4(( "af_latin_stretch_bottom_tilde: min y: %ld, max y: %ld\n", + min_y, max_y )); + + height = SUB_LONG( max_y, min_y ); + extremum_threshold = height / 8; + + do + { + p = p->next; + + if ( !( p->flags & AF_FLAG_CONTROL ) && + p->prev->y == p->y && p->next->y == p->y && + p->y != min_y && p->y != max_y && + p->prev->flags & AF_FLAG_CONTROL && + p->next->flags & AF_FLAG_CONTROL ) + { + AF_Point prev_on = p->prev; + AF_Point next_on = p->next; + + FT_Pos measurement; + + + while ( prev_on->flags & AF_FLAG_CONTROL ) + prev_on = prev_on->prev; + while ( next_on->flags & AF_FLAG_CONTROL ) + next_on = next_on->next; + + if ( next_on->y > p->y && prev_on->y > p->y ) + measurement = p->y - min_y; + else if ( next_on->y < p->y && prev_on->y < p->y ) + measurement = max_y - p->y; + else + continue; + + if ( measurement < extremum_threshold ) + continue; + + if ( !measurement_taken || measurement < min_measurement ) + { + measurement_taken = TRUE; + min_measurement = measurement; + } + } + + } while ( p != first_point ); + + if ( !measurement_taken ) + min_measurement = 0; + + FT_TRACE4(( "af_latin_stretch_bottom_tilde: min measurement %ld\n", + min_measurement )); + + af_touch_bottom_contours( hints, tilde_contour ); + + target_height = min_measurement + 64; + if ( height >= target_height ) + return 0; + + p = first_point; + do + { + p = p->next; + p->y = ( ( p->y - max_y ) * target_height / height ) + max_y; + + } while ( p != first_point ); + + return target_height - height; + } + + + /* + As part of `af_latin_stretch_top_tilde`, normally all points in the + tilde are marked as touched, so the existing grid fitting will leave the + tilde misaligned with the grid. + + This function moves the tilde contour down to be grid-fitted. We assume + that if moving the tilde down would cause it to touch or overlap another + countour, the vertical adjustment step will fix it. + + Because the vertical adjustment step comes after all other grid-fitting + steps, the top edge of the contour under the tilde is usually aligned + with a horizontal grid line. The vertical gap enforced by the vertical + adjustment is exactly one pixel, so if the top edge of the contour below + the tilde is on a grid line, the resulting tilde contour will also be + grid-aligned. + + But in cases where the gap is already big enough so that the vertical + adjustment does nothing, this function ensures that even without the + intervention of the vertical adjustment step, the tilde will be + grid-aligned. + + Return the vertical alignment amount. + */ + static FT_Pos + af_latin_align_top_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = p->y; + FT_Pos max_y = p->y; + + FT_Pos min_y_rounded; + FT_Pos delta; + FT_Pos height; + + + /* Find vertical extrema of the (now stretched) tilde contour. */ + do + { + p = p->next; + if ( p->y < min_y ) + min_y = p->y; + if ( p->y > max_y ) + max_y = p->y; + + } while ( p != first_point ); + + /* Align bottom of the tilde to the grid. */ + min_y_rounded = FT_PIX_ROUND( min_y ); + delta = min_y_rounded - min_y; + height = max_y - min_y; + + /* If the tilde is less than 3 pixels tall, snap the center of it */ + /* to the grid instead of the bottom to improve readability. */ + if ( height < 64 * 3 ) + delta += ( FT_PIX_ROUND( height ) - height ) / 2; + + af_move_contour_vertically( first_point, delta ); + + return delta; + } + + + static FT_Pos + af_latin_align_bottom_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = p->y; + FT_Pos max_y = p->y; + + FT_Pos max_y_rounded; + FT_Pos delta; + FT_Pos height; + + + do + { + p = p->next; + if ( p->y < min_y ) + min_y = p->y; + if ( p->y > max_y ) + max_y = p->y; + + } while ( p != first_point ); + + max_y_rounded = FT_PIX_ROUND( max_y ); + delta = max_y_rounded - max_y; + height = max_y - min_y; + + if ( height < 64 * 3 ) + delta -= ( FT_PIX_ROUND( height ) - height ) / 2; + + af_move_contour_vertically( first_point, delta ); + + return delta; + } + + + /* Return 1 if the given contour overlaps horizontally with the bounding */ + /* box of all other contours combined. This is a helper for function */ + /* `af_glyph_hints_apply_vertical_separation_adjustments`. */ + static FT_Bool + af_check_contour_horizontal_overlap( AF_GlyphHints hints, + FT_Int contour_index ) + { + FT_Pos contour_max_x = FT_LONG_MIN; + FT_Pos contour_min_x = FT_LONG_MAX; + FT_Pos others_max_x = FT_LONG_MIN; + FT_Pos others_min_x = FT_LONG_MAX; + + FT_Int contour; + + FT_Bool horizontal_overlap; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + AF_Point first_point = hints->contours[contour]; + AF_Point p = first_point; + + + /* Ignore dimensionless contours (i.e., contours with only one or */ + /* two points). */ + if ( first_point->next->next == first_point ) + continue; + + do + { + p = p->next; + + if ( contour == contour_index ) + { + if ( p->x < contour_min_x ) + contour_min_x = p->x; + if ( p->x > contour_max_x ) + contour_max_x = p->x; + } + else + { + if ( p->x < others_min_x ) + others_min_x = p->x; + if ( p->x > others_max_x ) + others_max_x = p->x; + } + } while ( p != first_point ); + } + + horizontal_overlap = + ( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) || + ( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) || + ( contour_max_x >= others_max_x && contour_min_x <= others_min_x ); + + return horizontal_overlap; + } + + + static void + af_glyph_hints_apply_vertical_separation_adjustments( + AF_GlyphHints hints, + AF_Dimension dim, + FT_UInt glyph_index, + FT_Pos accent_height_limit, + FT_Hash reverse_charmap ) + { + FT_Bool adjust_top = FALSE; + FT_Bool adjust_below_top = FALSE; + + FT_Bool adjust_bottom = FALSE; + FT_Bool adjust_above_bottom = FALSE; + + size_t* val; + FT_UInt32 adj_type = AF_ADJUST_NONE; + + + FT_TRACE4(( "Entering" + " af_glyph_hints_apply_vertical_separation_adjustments\n" )); + + if ( dim != AF_DIMENSION_VERT ) + return; + + val = ft_hash_num_lookup( (FT_Int)glyph_index, reverse_charmap ); + if ( val ) + { + FT_UInt codepoint = *val; + + + adj_type = af_adjustment_database_lookup( codepoint ); + + if ( adj_type ) + { + adjust_top = !!( adj_type & AF_ADJUST_UP ); + adjust_below_top = !!( adj_type & AF_ADJUST_UP2 ); + + adjust_bottom = !!( adj_type & AF_ADJUST_DOWN ); + adjust_above_bottom = !!( adj_type & AF_ADJUST_DOWN2 ); + } + } + + if ( ( ( adjust_top || adjust_bottom ) && + hints->num_contours >= 2 ) || + ( ( adjust_below_top || adjust_above_bottom ) && + hints->num_contours >= 3 ) ) + { + /* Recompute vertical extrema, this time acting on already */ + /* auto-hinted outlines. */ + af_compute_vertical_extrema( hints ); + } + + if ( ( adjust_top && hints->num_contours >= 2 ) || + ( adjust_below_top && hints->num_contours >= 3 ) ) + { + FT_Int high_contour; + FT_Pos high_min_y; + FT_Pos high_max_y; + FT_Pos high_height; + + FT_Int tilde_contour; + FT_Pos tilde_min_y; + FT_Pos tilde_max_y; + FT_Pos tilde_height; + + FT_Int contour; + FT_Bool horizontal_overlap; + + FT_Pos min_distance = 64; + FT_Pos adjustment_amount; + FT_Pos calculated_amount; + FT_Pos centering_adjustment = 0; + FT_Pos pos; + + FT_Bool is_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP ); + FT_Bool is_below_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP2 ); + + + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " Applying vertical adjustment: %s\n", + adjust_top ? "AF_ADJUST_TOP" : "AF_ADJUST_TOP2" )); + + high_contour = adjust_below_top + ? af_find_second_highest_contour( hints ) + : af_find_highest_contour( hints ); + + /* Check for a horizontal overlap between the high contour and the */ + /* rest. If there is no overlap, do not adjust. */ + horizontal_overlap = + af_check_contour_horizontal_overlap( hints, high_contour ); + if ( !horizontal_overlap ) + { + FT_TRACE4(( " High contour does not horizontally overlap" + " with other contours.\n" + " Skipping adjustment.\n" )); + return; + } + + high_min_y = hints->contour_y_minima[high_contour]; + high_max_y = hints->contour_y_maxima[high_contour]; + high_height = high_max_y - high_min_y; + + if ( high_height > accent_height_limit ) + { + FT_TRACE4(( " High contour height (%.2f) exceeds accent height" + " limit (%.2f).\n" + " Skipping adjustment.\n", + (double)high_height / 64, + (double)accent_height_limit / 64 )); + return; + } + + /* If the difference between the vertical minimum of the high */ + /* contour and the vertical maximum of another contour is less */ + /* than a pixel, shift up the high contour to make the distance */ + /* one pixel. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y; + FT_Pos max_y; + FT_Pos distance; + + + if ( contour == high_contour ) + continue; + + min_y = hints->contour_y_minima[contour]; + max_y = hints->contour_y_maxima[contour]; + + /* We also check that the y minimum of the 'other' contour */ + /* is below the high contour to avoid potential false hits */ + /* with contours enclosed in the high one. */ + distance = high_min_y - max_y; + if ( distance < 64 && + distance < min_distance && + min_y < high_min_y ) + min_distance = distance; + } + + adjustment_amount = 64 - min_distance; + + if ( is_top_tilde || is_below_top_tilde ) + { + tilde_contour = adjust_top + ? high_contour + : ( is_below_top_tilde + ? high_contour + : af_find_highest_contour( hints ) ); + + tilde_min_y = hints->contour_y_minima[tilde_contour]; + tilde_max_y = hints->contour_y_maxima[tilde_contour]; + tilde_height = tilde_max_y - tilde_min_y; + + /* The vertical separation adjustment potentially undoes a */ + /* tilde center alignment. If it would grid-align a tilde */ + /* less than 3 pixels in height, shift additionally to */ + /* re-center the tilde. */ + + pos = high_min_y + adjustment_amount; + if ( adjust_below_top && is_top_tilde ) + pos += high_height; + + if ( pos % 64 == 0 && tilde_height < 3 * 64 ) + { + centering_adjustment = ( FT_PIX_ROUND( tilde_height ) - + tilde_height ) / 2; + + FT_TRACE4(( " Additional tilde centering adjustment: %ld\n", + centering_adjustment )); + } + } + + if ( ( adjust_top && is_top_tilde ) || + ( adjust_below_top && is_below_top_tilde ) ) + calculated_amount = adjustment_amount + centering_adjustment; + else + calculated_amount = adjustment_amount; + + /* allow a delta of 2/64px to handle rounding differences */ + FT_TRACE4(( " Calculated adjustment amount: %ld%s\n", + calculated_amount, + ( calculated_amount < -2 || + ( adjustment_amount > 66 && calculated_amount > 66 ) ) + ? " (out of range [-2;66], not adjusting)" : "" )); + + if ( calculated_amount != 0 && + calculated_amount >= -2 && + ( calculated_amount <= 66 || adjustment_amount <= 66 ) ) + { + /* Value 8 is heuristic. */ + FT_Pos height_delta = high_height / 8; + FT_Pos min_y_limit = high_min_y - height_delta; + + + FT_TRACE4(( " Pushing high contour %ld units up\n", + calculated_amount )); + + /* While we use only a single contour (the 'high' one) for */ + /* computing `adjustment_amount`, we apply it to all contours */ + /* that are (approximately) in the same vertical range or */ + /* higher. This covers, for example, the inner contour of */ + /* the Czech ring accent or the second acute accent in the */ + /* Hungarian double acute accent. */ + af_move_contours_up( hints, min_y_limit, adjustment_amount ); + + if ( adjust_below_top && is_top_tilde ) + { + FT_TRACE4(( " Pushing top tilde %ld units up\n", + centering_adjustment )); + + af_move_contours_up( hints, + min_y_limit + high_height, + centering_adjustment ); + } + } + } + + if ( ( adjust_bottom && hints->num_contours >= 2 ) || + ( adjust_above_bottom && hints->num_contours >= 3 ) ) + { + FT_Int low_contour; + FT_Pos low_min_y; + FT_Pos low_max_y; + FT_Pos low_height; + + FT_Int tilde_contour; + FT_Pos tilde_min_y; + FT_Pos tilde_max_y; + FT_Pos tilde_height; + + FT_Int contour; + FT_Bool horizontal_overlap; + + FT_Pos min_distance = 64; + FT_Pos adjustment_amount; + FT_Pos calculated_amount; + FT_Pos centering_adjustment = 0; + FT_Pos pos; + + FT_Bool is_bottom_tilde = + !!( adj_type & AF_ADJUST_TILDE_BOTTOM ); + FT_Bool is_above_bottom_tilde = + !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 ); + + + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " Applying vertical adjustment: %s\n", + adjust_bottom ? "AF_ADJUST_DOWN": "AF_ADJUST_DOWN2" )); + + low_contour = adjust_above_bottom + ? af_find_second_lowest_contour( hints ) + : af_find_lowest_contour( hints ); + + horizontal_overlap = + af_check_contour_horizontal_overlap( hints, low_contour ); + if ( !horizontal_overlap ) + { + FT_TRACE4(( " Low contour does not horizontally overlap" + " with other contours.\n" + " Skipping adjustment.\n" )); + return; + } + + low_min_y = hints->contour_y_minima[low_contour]; + low_max_y = hints->contour_y_maxima[low_contour]; + low_height = low_max_y - low_min_y; + + if ( low_height > accent_height_limit ) + { + FT_TRACE4(( " Low contour height (%.2f) exceeds accent height" + " limit (%.2f).\n" + " Skipping adjustment.\n", + (double)low_height / 64, + (double)accent_height_limit / 64 )); + return; + } + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y; + FT_Pos max_y; + FT_Pos distance; + + + if ( contour == low_contour ) + continue; + + min_y = hints->contour_y_minima[contour]; + max_y = hints->contour_y_maxima[contour]; + + distance = min_y - low_max_y; + if ( distance < 64 && + distance < min_distance && + max_y > low_max_y ) + min_distance = distance; + } + + adjustment_amount = 64 - min_distance; + + if ( is_bottom_tilde || is_above_bottom_tilde ) + { + tilde_contour = adjust_bottom + ? low_contour + : ( is_above_bottom_tilde + ? low_contour + : af_find_lowest_contour( hints ) ); + + tilde_min_y = hints->contour_y_minima[tilde_contour]; + tilde_max_y = hints->contour_y_maxima[tilde_contour]; + tilde_height = tilde_max_y - tilde_min_y; + + pos = low_max_y - adjustment_amount; + if ( adjust_above_bottom && is_bottom_tilde ) + pos -= low_height; + + if ( pos % 64 == 0 && tilde_height < 3 * 64 ) + { + centering_adjustment = ( FT_PIX_ROUND( tilde_height ) - + tilde_height ) / 2; + + FT_TRACE4(( " Additional tilde centering adjustment: %ld\n", + centering_adjustment )); + } + } + + if ( ( adjust_bottom && is_bottom_tilde ) || + ( adjust_above_bottom && is_above_bottom_tilde ) ) + calculated_amount = adjustment_amount + centering_adjustment; + else + calculated_amount = adjustment_amount; + + FT_TRACE4(( " Calculated adjustment amount: %ld%s\n", + calculated_amount, + ( calculated_amount < -2 || + ( adjustment_amount > 66 && calculated_amount > 66 ) ) + ? " (out of range [-2;66], not adjusting)" : "" )); + + if ( calculated_amount != 0 && + calculated_amount >= -2 && + ( calculated_amount <= 66 || adjustment_amount <= 66 ) ) + { + FT_Pos height_delta = low_height / 8; + FT_Pos max_y_limit = low_max_y + height_delta; + + + FT_TRACE4(( " Pushing low contour %ld units down\n", + calculated_amount )); + + af_move_contours_down( hints, max_y_limit, adjustment_amount ); + + if ( adjust_above_bottom && is_bottom_tilde ) + { + FT_TRACE4(( " Pushing bottom tilde %ld units down\n", + centering_adjustment )); + + af_move_contours_down( hints, + max_y_limit - low_height, + centering_adjustment ); + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( ( ( adjust_top || adjust_bottom ) && + hints->num_contours >= 2 ) || + ( ( adjust_below_top || adjust_above_bottom ) && + hints->num_contours >= 3 ) ) ) + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " No vertical adjustment applied\n" )); +#endif + + FT_TRACE4(( "Exiting" + " af_glyph_hints_apply_vertical_separation_adjustments\n" )); + } + + +#undef FT_COMPONENT +#define FT_COMPONENT aflatin + + /* Compute the snapped width of a given stem, ignoring very thin ones. */ /* There is a lot of voodoo in this function; changing the hard-coded */ /* parameters influence the whole hinting process. */ @@ -2998,13 +4214,15 @@ af_latin_hint_edges( AF_GlyphHints hints, AF_Dimension dim ) { - AF_AxisHints axis = &hints->axis[dim]; - AF_Edge edges = axis->edges; - AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); - FT_PtrDist n_edges; - AF_Edge edge; - AF_Edge anchor = NULL; - FT_Int has_serifs = 0; + AF_AxisHints axis = &hints->axis[dim]; + + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + FT_PtrDist n_edges; + + AF_Edge anchor = NULL; + FT_Bool has_non_stem_edges = 0; AF_StyleClass style_class = hints->metrics->style_class; AF_ScriptClass script_class = af_script_classes[style_class->script]; @@ -3131,7 +4349,7 @@ edge2 = edge->link; if ( !edge2 ) { - has_serifs++; + has_non_stem_edges = TRUE; continue; } @@ -3408,7 +4626,7 @@ } } - if ( has_serifs || !anchor ) + if ( has_non_stem_edges || !anchor ) { /* * now hint the remaining edges (serifs and single) in order @@ -3426,9 +4644,75 @@ if ( edge->serif ) { + AF_Edge e, top, bottom; + FT_Pos min_pos, max_pos; + + + /* Check whether we have a real serif -- if there are */ + /* other edges with overlapping (or enclosed) segments */ + /* between the primary and serif edge, we have not. */ + /* */ + /* Such a situation might happen if an accent is very */ + /* near to its base glyph (for example, Vietnamese */ + /* uppercase letters with two accents in `arial.ttf`), */ + /* and the segment detection algorithm classifies the */ + /* top of the accent incorrectly as a serif. */ delta = edge->serif->opos - edge->opos; if ( delta < 0 ) + { delta = -delta; + + top = edge; + bottom = edge->serif; + } + else + { + top = edge->serif; + bottom = edge; + } + + if ( delta < 64 + 32 ) + { + /* take care of outline orientation while computing extrema */ + min_pos = FT_MIN( FT_MIN( FT_MIN( top->first->first->v, + top->first->last->v ), + FT_MIN( top->last->first->v, + top->last->last->v ) ), + FT_MIN( FT_MIN( bottom->first->first->v, + bottom->first->last->v ), + FT_MIN( bottom->last->first->v, + bottom->last->last->v ) ) ); + max_pos = FT_MAX( FT_MAX( FT_MAX( top->first->first->v, + top->first->last->v ), + FT_MAX( top->last->first->v, + top->last->last->v ) ), + FT_MAX( FT_MAX( bottom->first->first->v, + bottom->first->last->v ), + FT_MAX( bottom->last->first->v, + bottom->last->last->v ) ) ); + + for ( e = bottom + 1; e < top; e++ ) + { + FT_Pos e_min = FT_MIN( FT_MIN( e->first->first->v, + e->first->last->v ), + FT_MIN( e->last->first->v, + e->last->last->v ) ); + FT_Pos e_max = FT_MAX( FT_MAX( e->first->first->v, + e->first->last->v ), + FT_MAX( e->last->first->v, + e->last->last->v ) ); + + if ( !( ( e_min < min_pos && e_max < min_pos ) || + ( e_min > max_pos && e_max > max_pos ) ) ) + { + delta = 1000; /* not a real serif */ + break; + } + } + + if ( delta == 1000 ) + continue; + } } if ( delta < 64 + 16 ) @@ -3562,6 +4846,8 @@ AF_LatinAxis axis; + FT_Pos accent_height_limit = 0; + error = af_glyph_hints_reload( hints, outline ); if ( error ) @@ -3581,11 +4867,172 @@ if ( AF_HINTS_DO_VERTICAL( hints ) ) { + size_t* val; + + FT_Int top_tilde_contour = 0; + FT_Int bottom_tilde_contour = 0; + + FT_Int below_top_tilde_contour = 0; + FT_Int above_bottom_tilde_contour = 0; + + AF_LatinBlue capital_top_blue = NULL; + AF_LatinBlue capital_bottom_blue = NULL; + + AF_LatinBlue small_top_blue = NULL; + AF_LatinBlue small_bottom_blue = NULL; + + FT_Bool have_flags = FALSE; + + FT_Bool is_top_tilde = FALSE; + FT_Bool is_bottom_tilde = FALSE; + + FT_Bool is_below_top_tilde = FALSE; + FT_Bool is_above_bottom_tilde = FALSE; + + FT_Bool ignore_capital_top = FALSE; + FT_Bool ignore_capital_bottom = FALSE; + + FT_Bool ignore_small_top = FALSE; + FT_Bool ignore_small_bottom = FALSE; + + FT_Bool do_height_check = TRUE; + + FT_Pos limit; + FT_Pos y_offset; + + + val = ft_hash_num_lookup( (FT_Int)glyph_index, + metrics->root.reverse_charmap ); + if ( val ) + { + FT_UInt codepoint = *val; + FT_UInt32 adj_type = af_adjustment_database_lookup( codepoint ); + + + if ( adj_type ) + { + have_flags = !!adj_type; + + is_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP ); + is_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM ); + + is_below_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP2 ); + is_above_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 ); + + ignore_capital_top = !!( adj_type & AF_IGNORE_CAPITAL_TOP ); + ignore_capital_bottom = !!( adj_type & AF_IGNORE_CAPITAL_BOTTOM ); + + ignore_small_top = !!( adj_type & AF_IGNORE_SMALL_TOP ); + ignore_small_bottom = !!( adj_type & AF_IGNORE_SMALL_BOTTOM ); + + do_height_check = !( adj_type & AF_ADJUST_NO_HEIGHT_CHECK ); + } + } + + if ( is_top_tilde || is_bottom_tilde || + is_below_top_tilde || is_above_bottom_tilde ) + af_compute_vertical_extrema( hints ); + + /* Process inner tilde glyphs first. */ + if ( is_below_top_tilde ) + { + below_top_tilde_contour = af_find_second_highest_contour( hints ); + + y_offset = af_latin_stretch_top_tilde( + hints, below_top_tilde_contour ); + y_offset += af_latin_align_top_tilde( + hints, below_top_tilde_contour ); + + limit = hints->contour_y_minima[below_top_tilde_contour]; + af_move_contours_up( hints, limit, y_offset ); + } + if ( is_above_bottom_tilde ) + { + above_bottom_tilde_contour = af_find_second_lowest_contour( hints ); + + y_offset = af_latin_stretch_bottom_tilde( + hints, above_bottom_tilde_contour ); + y_offset -= af_latin_align_bottom_tilde( + hints, above_bottom_tilde_contour ); + + limit = hints->contour_y_maxima[above_bottom_tilde_contour]; + af_move_contours_down( hints, limit, y_offset ); + } + + if ( is_top_tilde ) + { + top_tilde_contour = af_find_highest_contour( hints ); + + (void)af_latin_stretch_top_tilde( hints, top_tilde_contour ); + (void)af_latin_align_top_tilde( hints, top_tilde_contour ); + } + if ( is_bottom_tilde ) + { + bottom_tilde_contour = af_find_lowest_contour( hints ); + + (void)af_latin_stretch_bottom_tilde( hints, bottom_tilde_contour ); + (void)af_latin_align_bottom_tilde( hints, bottom_tilde_contour ); + } + axis = &metrics->axis[AF_DIMENSION_VERT]; error = af_latin_hints_detect_features( hints, axis->width_count, axis->widths, AF_DIMENSION_VERT ); + + if ( have_flags ) + { + af_latin_get_base_glyph_blues( hints, + TRUE, + &capital_top_blue, + &capital_bottom_blue ); + af_latin_get_base_glyph_blues( hints, + FALSE, + &small_top_blue, + &small_bottom_blue ); + + if ( do_height_check ) + { + /* Set a heuristic limit for the accent height so that */ + /* `af_glyph_hints_apply_vertical_separation_adjustments` */ + /* can correctly ignore the case where an accent is */ + /* unexpectedly not the highest (or lowest) contour. */ + + /* Either 2/3 of the lowercase blue zone height... */ + if ( small_top_blue && small_bottom_blue ) + accent_height_limit = 2 * ( small_top_blue->shoot.cur - + small_bottom_blue->shoot.cur ) / 3; + /* or 1/2 of the uppercase blue zone height... */ + else if ( capital_top_blue && capital_bottom_blue ) + accent_height_limit = ( capital_top_blue->shoot.cur - + capital_bottom_blue->shoot.cur ) / 2; + /* or half of the standard PostScript ascender value (8/10) */ + /* of the EM value, scaled. */ + else + accent_height_limit = FT_MulFix( metrics->units_per_em * 4 / 10, + metrics->root.scaler.y_scale ); + } + } + + if ( capital_top_blue && capital_bottom_blue ) + { + if ( ignore_capital_top ) + af_latin_ignore_top( hints, + capital_top_blue, capital_bottom_blue ); + if ( ignore_capital_bottom ) + af_latin_ignore_bottom( hints, + capital_top_blue, capital_bottom_blue ); + } + if ( small_top_blue && small_bottom_blue ) + { + if ( ignore_small_top ) + af_latin_ignore_top( hints, + small_top_blue, small_bottom_blue ); + if ( ignore_small_bottom ) + af_latin_ignore_bottom( hints, + small_top_blue, small_bottom_blue ); + } + if ( error ) goto Exit; @@ -3604,6 +5051,12 @@ af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + af_glyph_hints_apply_vertical_separation_adjustments( + hints, + (AF_Dimension)dim, + glyph_index, + accent_height_limit, + metrics->root.reverse_charmap ); } } @@ -3632,7 +5085,7 @@ (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */ (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */ - (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done, /* style_metrics_done */ (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */ (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h index 54e50615021..82b4b0d480d 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for latin writing system * (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -61,17 +61,26 @@ FT_BEGIN_HEADER ( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT ) #define AF_LATIN_IS_LONG_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG ) +#define AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM ) +#define AF_LATIN_IS_SMALL_BOTTOM_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM ) #define AF_LATIN_MAX_WIDTHS 16 -#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ -#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ -#define AF_LATIN_BLUE_SUB_TOP ( 1U << 2 ) /* we have a subscript top */ - /* blue zone */ -#define AF_LATIN_BLUE_NEUTRAL ( 1U << 3 ) /* we have neutral blue zone */ -#define AF_LATIN_BLUE_ADJUSTMENT ( 1U << 4 ) /* used for scale adjustment */ - /* optimization */ +#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ +#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ +#define AF_LATIN_BLUE_SUB_TOP ( 1U << 2 ) /* we have a subscript */ + /* top blue zone */ +#define AF_LATIN_BLUE_NEUTRAL ( 1U << 3 ) /* we have a neutral blue */ + /* zone */ +#define AF_LATIN_BLUE_ADJUSTMENT ( 1U << 4 ) /* used for scale adjustm. */ + /* optimization */ +#define AF_LATIN_BLUE_BOTTOM ( 1U << 5 ) /* we have a capital */ + /* letter bottom blue zone */ +#define AF_LATIN_BLUE_BOTTOM_SMALL ( 1U << 6 ) /* we have a small letter */ + /* bottom blue zone */ typedef struct AF_LatinBlueRec_ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c index af1d59a6896..d84adc09679 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.c @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (body). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h index 99f0e15f92b..a04b4df0b3b 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afloader.h @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c index 726f6ca2b78..22d85a889e8 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.c @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (body). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -146,7 +146,7 @@ if ( !af_style_classes[ss] ) { - FT_TRACE2(( "af_property_set: Invalid value %d for property `%s'\n", + FT_TRACE2(( "af_property_set: Invalid value %u for property `%s'\n", *fallback_script, property_name )); return FT_THROW( Invalid_Argument ); } @@ -412,6 +412,11 @@ module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_init( module ); +#endif + return FT_Err_Ok; } @@ -421,6 +426,11 @@ { FT_UNUSED( ft_module ); +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_done( (AF_Module)ft_module ); +#endif + #ifdef FT_DEBUG_AUTOFIT if ( af_debug_hints_rec_->memory ) af_glyph_hints_done( af_debug_hints_rec_ ); diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h index 91a1abfef1f..c62421ef696 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afmodule.h @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (specification). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,6 +22,7 @@ #include #include +#include "ft-hb.h" FT_BEGIN_HEADER @@ -40,6 +41,11 @@ FT_BEGIN_HEADER FT_Bool no_stem_darkening; FT_Int darken_params[8]; +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_t* hb_funcs; +#endif + } AF_ModuleRec, *AF_Module; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c index 007b4328189..fd54948f3a5 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (body). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -73,9 +73,11 @@ { AF_UNIRANGE_REC( 0x0600, 0x06FF ), /* Arabic */ AF_UNIRANGE_REC( 0x0750, 0x07FF ), /* Arabic Supplement */ + AF_UNIRANGE_REC( 0x0870, 0x089F ), /* Arabic Extended-B */ AF_UNIRANGE_REC( 0x08A0, 0x08FF ), /* Arabic Extended-A */ AF_UNIRANGE_REC( 0xFB50, 0xFDFF ), /* Arabic Presentation Forms-A */ AF_UNIRANGE_REC( 0xFE70, 0xFEFF ), /* Arabic Presentation Forms-B */ + AF_UNIRANGE_REC( 0x10EC0, 0x10EFF ), /* Arabic Extended-C */ AF_UNIRANGE_REC( 0x1EE00, 0x1EEFF ), /* Arabic Mathematical Alphabetic Symbols */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -90,8 +92,9 @@ AF_UNIRANGE_REC( 0x06DF, 0x06E4 ), AF_UNIRANGE_REC( 0x06E7, 0x06E8 ), AF_UNIRANGE_REC( 0x06EA, 0x06ED ), - AF_UNIRANGE_REC( 0x08D4, 0x08E1 ), - AF_UNIRANGE_REC( 0x08D3, 0x08FF ), + AF_UNIRANGE_REC( 0x0897, 0x089F ), + AF_UNIRANGE_REC( 0x08CA, 0x08E1 ), + AF_UNIRANGE_REC( 0x08E3, 0x08FF ), AF_UNIRANGE_REC( 0xFBB2, 0xFBC1 ), AF_UNIRANGE_REC( 0xFE70, 0xFE70 ), AF_UNIRANGE_REC( 0xFE72, 0xFE72 ), @@ -101,6 +104,7 @@ AF_UNIRANGE_REC( 0xFE7A, 0xFE7A ), AF_UNIRANGE_REC( 0xFE7C, 0xFE7C ), AF_UNIRANGE_REC( 0xFE7E, 0xFE7E ), + AF_UNIRANGE_REC( 0x10EFD, 0x10EFF ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -198,8 +202,9 @@ const AF_Script_UniRangeRec af_cans_uniranges[] = { - AF_UNIRANGE_REC( 0x1400, 0x167F ), /* Unified Canadian Aboriginal Syllabics */ - AF_UNIRANGE_REC( 0x18B0, 0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended */ + AF_UNIRANGE_REC( 0x1400, 0x167F ), /* Unified Canadian Aboriginal Syllabics */ + AF_UNIRANGE_REC( 0x18B0, 0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended */ + AF_UNIRANGE_REC( 0x11AB0, 0x11ABF ), /* Unified Canadian Aboriginal Syllabics Extended-A */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -259,6 +264,9 @@ }; + /* TODO: Split off data for new 'cyrb' (subscript) and 'cyrp' */ + /* (superscript) groups (mainly from the Extended-D block), */ + /* in analogy to 'latb' and 'latp'? */ const AF_Script_UniRangeRec af_cyrl_uniranges[] = { AF_UNIRANGE_REC( 0x0400, 0x04FF ), /* Cyrillic */ @@ -266,6 +274,7 @@ AF_UNIRANGE_REC( 0x2DE0, 0x2DFF ), /* Cyrillic Extended-A */ AF_UNIRANGE_REC( 0xA640, 0xA69F ), /* Cyrillic Extended-B */ AF_UNIRANGE_REC( 0x1C80, 0x1C8F ), /* Cyrillic Extended-C */ + AF_UNIRANGE_REC( 0x1E030, 0x1E08F ), /* Cyrillic Extended-D */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -285,15 +294,16 @@ const AF_Script_UniRangeRec af_deva_uniranges[] = { - AF_UNIRANGE_REC( 0x0900, 0x093B ), /* Devanagari */ + AF_UNIRANGE_REC( 0x0900, 0x093B ), /* Devanagari */ /* omitting U+093C nukta */ - AF_UNIRANGE_REC( 0x093D, 0x0950 ), /* ... continued */ + AF_UNIRANGE_REC( 0x093D, 0x0950 ), /* ... continued */ /* omitting U+0951 udatta, U+0952 anudatta */ - AF_UNIRANGE_REC( 0x0953, 0x0963 ), /* ... continued */ + AF_UNIRANGE_REC( 0x0953, 0x0963 ), /* ... continued */ /* omitting U+0964 danda, U+0965 double danda */ - AF_UNIRANGE_REC( 0x0966, 0x097F ), /* ... continued */ - AF_UNIRANGE_REC( 0x20B9, 0x20B9 ), /* (new) Rupee sign */ - AF_UNIRANGE_REC( 0xA8E0, 0xA8FF ), /* Devanagari Extended */ + AF_UNIRANGE_REC( 0x0966, 0x097F ), /* ... continued */ + AF_UNIRANGE_REC( 0x20B9, 0x20B9 ), /* (new) Rupee sign */ + AF_UNIRANGE_REC( 0xA8E0, 0xA8FF ), /* Devanagari Extended */ + AF_UNIRANGE_REC( 0x11B00, 0x11B5F ), /* Devanagari Extended-A */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -329,6 +339,7 @@ AF_UNIRANGE_REC( 0x1380, 0x139F ), /* Ethiopic Supplement */ AF_UNIRANGE_REC( 0x2D80, 0x2DDF ), /* Ethiopic Extended */ AF_UNIRANGE_REC( 0xAB00, 0xAB2F ), /* Ethiopic Extended-A */ + AF_UNIRANGE_REC( 0x1E7E0, 0x1E7FF ), /* Ethiopic Extended-B */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -534,7 +545,7 @@ { AF_UNIRANGE_REC( 0x0EB1, 0x0EB1 ), AF_UNIRANGE_REC( 0x0EB4, 0x0EBC ), - AF_UNIRANGE_REC( 0x0EC8, 0x0ECD ), + AF_UNIRANGE_REC( 0x0EC8, 0x0ECE ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -567,12 +578,15 @@ AF_UNIRANGE_REC( 0x2C7E, 0x2C7F ), /* ... continued */ AF_UNIRANGE_REC( 0x2E00, 0x2E7F ), /* Supplemental Punctuation */ AF_UNIRANGE_REC( 0xA720, 0xA76F ), /* Latin Extended-D */ - AF_UNIRANGE_REC( 0xA771, 0xA7F7 ), /* ... continued */ + AF_UNIRANGE_REC( 0xA771, 0xA7F0 ), /* ... continued */ + AF_UNIRANGE_REC( 0xA7F2, 0xA7F7 ), /* ... continued */ AF_UNIRANGE_REC( 0xA7FA, 0xA7FF ), /* ... continued */ AF_UNIRANGE_REC( 0xAB30, 0xAB5B ), /* Latin Extended-E */ - AF_UNIRANGE_REC( 0xAB60, 0xAB6F ), /* ... continued */ + AF_UNIRANGE_REC( 0xAB60, 0xAB68 ), /* ... continued */ + AF_UNIRANGE_REC( 0xAB6A, 0xAB6F ), /* ... continued */ AF_UNIRANGE_REC( 0xFB00, 0xFB06 ), /* Alphab. Present. Forms (Latin Ligs) */ AF_UNIRANGE_REC( 0x1D400, 0x1D7FF ), /* Mathematical Alphanumeric Symbols */ + AF_UNIRANGE_REC( 0x1DF00, 0x1DFFF ), /* Latin Extended-G */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -588,7 +602,7 @@ AF_UNIRANGE_REC( 0x02B9, 0x02DF ), AF_UNIRANGE_REC( 0x02E5, 0x02FF ), AF_UNIRANGE_REC( 0x0300, 0x036F ), - AF_UNIRANGE_REC( 0x1AB0, 0x1ABE ), + AF_UNIRANGE_REC( 0x1AB0, 0x1AEB ), AF_UNIRANGE_REC( 0x1DC0, 0x1DFF ), AF_UNIRANGE_REC( 0x2017, 0x2017 ), AF_UNIRANGE_REC( 0x203E, 0x203E ), @@ -625,8 +639,11 @@ AF_UNIRANGE_REC( 0x2070, 0x207F ), /* superscript digits and letters */ AF_UNIRANGE_REC( 0x2C7D, 0x2C7D ), /* modifier letter capital v */ AF_UNIRANGE_REC( 0xA770, 0xA770 ), /* modifier letter us */ + AF_UNIRANGE_REC( 0xA7F1, 0xA7F1 ), /* modifier letter capital s */ AF_UNIRANGE_REC( 0xA7F8, 0xA7F9 ), /* more modifier letters */ AF_UNIRANGE_REC( 0xAB5C, 0xAB5F ), /* more modifier letters */ + AF_UNIRANGE_REC( 0xAB69, 0xAB69 ), /* modifier letter small turned w */ + AF_UNIRANGE_REC( 0x10780, 0x107FB ), /* Latin Extended-F */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -638,7 +655,8 @@ const AF_Script_UniRangeRec af_lisu_uniranges[] = { - AF_UNIRANGE_REC( 0xA4D0, 0xA4FF ), /* Lisu */ + AF_UNIRANGE_REC( 0xA4D0, 0xA4FF ), /* Lisu */ + AF_UNIRANGE_REC( 0x11FB0, 0x11FBF ), /* Lisu Supplement */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -696,6 +714,7 @@ AF_UNIRANGE_REC( 0x1000, 0x109F ), /* Myanmar */ AF_UNIRANGE_REC( 0xA9E0, 0xA9FF ), /* Myanmar Extended-B */ AF_UNIRANGE_REC( 0xAA60, 0xAA7F ), /* Myanmar Extended-A */ + AF_UNIRANGE_REC( 0x116D0, 0x116FF ), /* Myanmar Extended-C */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -836,6 +855,7 @@ const AF_Script_UniRangeRec af_sinh_nonbase_uniranges[] = { + AF_UNIRANGE_REC( 0x0D81, 0x0D81 ), AF_UNIRANGE_REC( 0x0DCA, 0x0DCA ), AF_UNIRANGE_REC( 0x0DD2, 0x0DD6 ), AF_UNIRANGE_REC( 0, 0 ) @@ -859,7 +879,8 @@ const AF_Script_UniRangeRec af_taml_uniranges[] = { - AF_UNIRANGE_REC( 0x0B80, 0x0BFF ), /* Tamil */ + AF_UNIRANGE_REC( 0x0B80, 0x0BFF ), /* Tamil */ + AF_UNIRANGE_REC( 0x11FC0, 0x11FFF ), /* Tamil Supplement */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -899,6 +920,7 @@ { AF_UNIRANGE_REC( 0x0C00, 0x0C00 ), AF_UNIRANGE_REC( 0x0C04, 0x0C04 ), + AF_UNIRANGE_REC( 0x0C3C, 0x0C3C ), AF_UNIRANGE_REC( 0x0C3E, 0x0C40 ), AF_UNIRANGE_REC( 0x0C46, 0x0C56 ), AF_UNIRANGE_REC( 0x0C62, 0x0C63 ), @@ -992,6 +1014,7 @@ AF_UNIRANGE_REC( 0xA806, 0xA806 ), AF_UNIRANGE_REC( 0xA80B, 0xA80B ), AF_UNIRANGE_REC( 0xA825, 0xA826 ), + AF_UNIRANGE_REC( 0xA82C, 0xA82C ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -1048,15 +1071,21 @@ AF_UNIRANGE_REC( 0xFE10, 0xFE1F ), /* Vertical forms */ AF_UNIRANGE_REC( 0xFE30, 0xFE4F ), /* CJK Compatibility Forms */ AF_UNIRANGE_REC( 0xFF00, 0xFFEF ), /* Halfwidth and Fullwidth Forms */ + AF_UNIRANGE_REC( 0x1AFF0, 0x1AFFF ), /* Kana Extended-B */ AF_UNIRANGE_REC( 0x1B000, 0x1B0FF ), /* Kana Supplement */ AF_UNIRANGE_REC( 0x1B100, 0x1B12F ), /* Kana Extended-A */ + AF_UNIRANGE_REC( 0x1B130, 0x1B16F ), /* Small Kana Extension */ AF_UNIRANGE_REC( 0x1D300, 0x1D35F ), /* Tai Xuan Hing Symbols */ AF_UNIRANGE_REC( 0x20000, 0x2A6DF ), /* CJK Unified Ideographs Extension B */ AF_UNIRANGE_REC( 0x2A700, 0x2B73F ), /* CJK Unified Ideographs Extension C */ AF_UNIRANGE_REC( 0x2B740, 0x2B81F ), /* CJK Unified Ideographs Extension D */ AF_UNIRANGE_REC( 0x2B820, 0x2CEAF ), /* CJK Unified Ideographs Extension E */ AF_UNIRANGE_REC( 0x2CEB0, 0x2EBEF ), /* CJK Unified Ideographs Extension F */ + AF_UNIRANGE_REC( 0x2EBF0, 0x2EE5D ), /* CJK Unified Ideographs Extension I */ AF_UNIRANGE_REC( 0x2F800, 0x2FA1F ), /* CJK Compatibility Ideographs Supplement */ + AF_UNIRANGE_REC( 0x30000, 0x3134A ), /* CJK Unified Ideographs Extension G */ + AF_UNIRANGE_REC( 0x31350, 0x323AF ), /* CJK Unified Ideographs Extension H */ + AF_UNIRANGE_REC( 0x323B0, 0x33479 ), /* CJK Unified Ideographs Extension J */ AF_UNIRANGE_REC( 0, 0 ) }; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h index 813b3ee78ef..fa00eb75046 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.h @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (specification). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h b/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h index 0a83d771501..5c4cbbcb922 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afscript.h @@ -4,7 +4,7 @@ * * Auto-fitter scripts (specification only). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c index df0f46ada89..f3c0744fd9d 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (body). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,8 +22,8 @@ #include "aftypes.h" #include "afshaper.h" -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ /************************************************************************** * @@ -89,17 +89,18 @@ #define SCRIPT( s, S, d, h, H, ss ) h, - static const hb_script_t scripts[] = + FT_LOCAL_ARRAY_DEF( hb_script_t ) + af_hb_scripts[] = { #include "afscript.h" }; - FT_Error - af_shaper_get_coverage( AF_FaceGlobals globals, - AF_StyleClass style_class, - FT_UShort* gstyles, - FT_Bool default_script ) + static FT_Error + af_shaper_get_coverage_hb( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) { hb_face_t* face; @@ -124,10 +125,10 @@ if ( !globals || !style_class || !gstyles ) return FT_THROW( Invalid_Argument ); - face = hb_font_get_face( globals->hb_font ); + face = hb( font_get_face )( globals->hb_font ); coverage_tags = coverages[style_class->coverage]; - script = scripts[style_class->script]; + script = af_hb_scripts[style_class->script]; /* Convert a HarfBuzz script tag into the corresponding OpenType */ /* tag or tags -- some Indic scripts like Devanagari have an old */ @@ -137,19 +138,19 @@ hb_tag_t tags[3]; - hb_ot_tags_from_script_and_language( script, - HB_LANGUAGE_INVALID, - &tags_count, - tags, - NULL, - NULL ); + hb( ot_tags_from_script_and_language )( script, + HB_LANGUAGE_INVALID, + &tags_count, + tags, + NULL, + NULL ); script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE; script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE; script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE; } - /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */ - /* HB_TAG_NONE except for the default script. */ + /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */ + /* HB_TAG_NONE except for the default script. */ if ( default_script ) { if ( script_tags[0] == HB_TAG_NONE ) @@ -170,15 +171,15 @@ goto Exit; } - gsub_lookups = hb_set_create(); - hb_ot_layout_collect_lookups( face, - HB_OT_TAG_GSUB, - script_tags, - NULL, - coverage_tags, - gsub_lookups ); + gsub_lookups = hb( set_create )(); + hb( ot_layout_collect_lookups )( face, + HB_OT_TAG_GSUB, + script_tags, + NULL, + coverage_tags, + gsub_lookups ); - if ( hb_set_is_empty( gsub_lookups ) ) + if ( hb( set_is_empty )( gsub_lookups ) ) goto Exit; /* nothing to do */ FT_TRACE4(( "GSUB lookups (style `%s'):\n", @@ -189,22 +190,22 @@ count = 0; #endif - gsub_glyphs = hb_set_create(); - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); ) + gsub_glyphs = hb( set_create )(); + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups, &idx ); ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; #endif /* get output coverage of GSUB feature */ - hb_ot_layout_lookup_collect_glyphs( face, - HB_OT_TAG_GSUB, - idx, - NULL, - NULL, - NULL, - gsub_glyphs ); + hb( ot_layout_lookup_collect_glyphs )( face, + HB_OT_TAG_GSUB, + idx, + NULL, + NULL, + NULL, + gsub_glyphs ); } #ifdef FT_DEBUG_LEVEL_TRACE @@ -218,34 +219,34 @@ af_style_names[style_class->style] )); FT_TRACE4(( " " )); - gpos_lookups = hb_set_create(); - hb_ot_layout_collect_lookups( face, - HB_OT_TAG_GPOS, - script_tags, - NULL, - coverage_tags, - gpos_lookups ); + gpos_lookups = hb( set_create )(); + hb( ot_layout_collect_lookups )( face, + HB_OT_TAG_GPOS, + script_tags, + NULL, + coverage_tags, + gpos_lookups ); #ifdef FT_DEBUG_LEVEL_TRACE count = 0; #endif - gpos_glyphs = hb_set_create(); - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); ) + gpos_glyphs = hb( set_create )(); + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gpos_lookups, &idx ); ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; #endif /* get input coverage of GPOS feature */ - hb_ot_layout_lookup_collect_glyphs( face, - HB_OT_TAG_GPOS, - idx, - NULL, - gpos_glyphs, - NULL, - NULL ); + hb( ot_layout_lookup_collect_glyphs )( face, + HB_OT_TAG_GPOS, + idx, + NULL, + gpos_glyphs, + NULL, + NULL ); } #ifdef FT_DEBUG_LEVEL_TRACE @@ -281,14 +282,14 @@ GET_UTF8_CHAR( ch, p ); - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, - &idx ); ) + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups, + &idx ); ) { hb_codepoint_t gidx = FT_Get_Char_Index( globals->face, ch ); - if ( hb_ot_layout_lookup_would_substitute( face, idx, - &gidx, 1, 1 ) ) + if ( hb( ot_layout_lookup_would_substitute )( face, idx, + &gidx, 1, 1 ) ) { found = 1; break; @@ -352,14 +353,14 @@ * */ if ( style_class->coverage != AF_COVERAGE_DEFAULT ) - hb_set_subtract( gsub_glyphs, gpos_glyphs ); + hb( set_subtract )( gsub_glyphs, gpos_glyphs ); #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE4(( " glyphs without GPOS data (`*' means already assigned)" )); count = 0; #endif - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); ) + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_glyphs, &idx ); ) { #ifdef FT_DEBUG_LEVEL_TRACE if ( !( count % 10 ) ) @@ -368,7 +369,7 @@ FT_TRACE4(( " " )); } - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; #endif @@ -397,10 +398,10 @@ #endif Exit: - hb_set_destroy( gsub_lookups ); - hb_set_destroy( gsub_glyphs ); - hb_set_destroy( gpos_lookups ); - hb_set_destroy( gpos_glyphs ); + hb( set_destroy )( gsub_lookups ); + hb( set_destroy )( gsub_glyphs ); + hb( set_destroy )( gpos_lookups ); + hb( set_destroy )( gpos_glyphs ); return FT_Err_Ok; } @@ -437,31 +438,33 @@ }; - void* - af_shaper_buf_create( FT_Face face ) + static void* + af_shaper_buf_create_hb( AF_FaceGlobals globals ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); - return (void*)hb_buffer_create(); + return (void*)hb( buffer_create )(); } - void - af_shaper_buf_destroy( FT_Face face, - void* buf ) + static void + af_shaper_buf_destroy_hb( AF_FaceGlobals globals, + void* buf ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); - hb_buffer_destroy( (hb_buffer_t*)buf ); + hb( buffer_destroy )( (hb_buffer_t*)buf ); } - const char* - af_shaper_get_cluster( const char* p, - AF_StyleMetrics metrics, - void* buf_, - unsigned int* count ) + static const char* + af_shaper_get_cluster_hb( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) { + AF_FaceGlobals globals = metrics->globals; + AF_StyleClass style_class; const hb_feature_t* feature; FT_Int upem; @@ -472,6 +475,8 @@ hb_font_t* font; hb_codepoint_t dummy; + FT_UNUSED( globals ); + upem = (FT_Int)metrics->globals->face->units_per_EM; style_class = metrics->style_class; @@ -480,7 +485,7 @@ font = metrics->globals->hb_font; /* we shape at a size of units per EM; this means font units */ - hb_font_set_scale( font, upem, upem ); + hb( font_set_scale )( font, upem, upem ); while ( *p == ' ' ) p++; @@ -492,15 +497,15 @@ len = (int)( q - p ); /* feed character(s) to the HarfBuzz buffer */ - hb_buffer_clear_contents( buf ); - hb_buffer_add_utf8( buf, p, len, 0, len ); + hb( buffer_clear_contents )( buf ); + hb( buffer_add_utf8 )( buf, p, len, 0, len ); /* we let HarfBuzz guess the script and writing direction */ - hb_buffer_guess_segment_properties( buf ); + hb( buffer_guess_segment_properties )( buf ); /* shape buffer, which means conversion from character codes to */ /* glyph indices, possibly applying a feature */ - hb_shape( font, buf, feature, feature ? 1 : 0 ); + hb( shape )( font, buf, feature, feature ? 1 : 0 ); if ( feature ) { @@ -517,13 +522,13 @@ /* glyph indices; otherwise the affected glyph or glyphs aren't */ /* available at all in the feature */ - hb_buffer_clear_contents( hb_buf ); - hb_buffer_add_utf8( hb_buf, p, len, 0, len ); - hb_buffer_guess_segment_properties( hb_buf ); - hb_shape( font, hb_buf, NULL, 0 ); + hb( buffer_clear_contents )( hb_buf ); + hb( buffer_add_utf8 )( hb_buf, p, len, 0, len ); + hb( buffer_guess_segment_properties )( hb_buf ); + hb( shape )( font, hb_buf, NULL, 0 ); - ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); - hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount ); + ginfo = hb( buffer_get_glyph_infos )( buf, &gcount ); + hb_ginfo = hb( buffer_get_glyph_infos )( hb_buf, &hb_gcount ); if ( gcount == hb_gcount ) { @@ -537,12 +542,12 @@ if ( i == gcount ) { /* both buffers have identical glyph indices */ - hb_buffer_clear_contents( buf ); + hb( buffer_clear_contents )( buf ); } } } - *count = hb_buffer_get_length( buf ); + *count = hb( buffer_get_length )( buf ); #ifdef FT_DEBUG_LEVEL_TRACE if ( feature && *count > 1 ) @@ -554,23 +559,25 @@ } - FT_ULong - af_shaper_get_elem( AF_StyleMetrics metrics, - void* buf_, - unsigned int idx, - FT_Long* advance, - FT_Long* y_offset ) + static FT_ULong + af_shaper_get_elem_hb( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) { + AF_FaceGlobals globals = metrics->globals; + hb_buffer_t* buf = (hb_buffer_t*)buf_; hb_glyph_info_t* ginfo; hb_glyph_position_t* gpos; unsigned int gcount; - FT_UNUSED( metrics ); + FT_UNUSED( globals ); - ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); - gpos = hb_buffer_get_glyph_positions( buf, &gcount ); + ginfo = hb( buffer_get_glyph_infos )( buf, &gcount ); + gpos = hb( buffer_get_glyph_positions )( buf, &gcount ); if ( idx >= gcount ) return 0; @@ -584,14 +591,14 @@ } -#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ - FT_Error - af_shaper_get_coverage( AF_FaceGlobals globals, - AF_StyleClass style_class, - FT_UShort* gstyles, - FT_Bool default_script ) + static FT_Error + af_shaper_get_coverage_nohb( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) { FT_UNUSED( globals ); FT_UNUSED( style_class ); @@ -602,29 +609,29 @@ } - void* - af_shaper_buf_create( FT_Face face ) + static void* + af_shaper_buf_create_nohb( AF_FaceGlobals globals ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); return NULL; } - void - af_shaper_buf_destroy( FT_Face face, - void* buf ) + static void + af_shaper_buf_destroy_nohb( AF_FaceGlobals globals, + void* buf ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); FT_UNUSED( buf ); } - const char* - af_shaper_get_cluster( const char* p, - AF_StyleMetrics metrics, - void* buf_, - unsigned int* count ) + static const char* + af_shaper_get_cluster_nohb( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) { FT_Face face = metrics->globals->face; FT_ULong ch, dummy = 0; @@ -656,12 +663,12 @@ } - FT_ULong - af_shaper_get_elem( AF_StyleMetrics metrics, - void* buf_, - unsigned int idx, - FT_Long* advance, - FT_Long* y_offset ) + static FT_ULong + af_shaper_get_elem_nohb( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) { FT_Face face = metrics->globals->face; FT_ULong glyph_index = *(FT_ULong*)buf_; @@ -684,7 +691,90 @@ } -#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + /********************************************************************/ + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( globals ) ) + return af_shaper_get_coverage_hb( globals, + style_class, + gstyles, + default_script ); + else +#endif + return af_shaper_get_coverage_nohb( globals, + style_class, + gstyles, + default_script ); + } + + + void* + af_shaper_buf_create( AF_FaceGlobals globals ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( globals ) ) + return af_shaper_buf_create_hb( globals ); + else +#endif + return af_shaper_buf_create_nohb( globals ); + } + + + void + af_shaper_buf_destroy( AF_FaceGlobals globals, + void* buf ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( globals ) ) + af_shaper_buf_destroy_hb( globals, buf ); + else +#endif + af_shaper_buf_destroy_nohb( globals, buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( metrics->globals ) ) + return af_shaper_get_cluster_hb( p, metrics, buf_, count ); + else +#endif + return af_shaper_get_cluster_nohb( p, metrics, buf_, count ); + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( metrics->globals ) ) + return af_shaper_get_elem_hb( metrics, + buf_, + idx, + advance, + y_offset ); +#endif + return af_shaper_get_elem_nohb( metrics, + buf_, + idx, + advance, + y_offset ); + } /* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h index 2eb03bb5d98..757368fc9c0 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.h @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (specification). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -23,17 +23,14 @@ #include +FT_BEGIN_HEADER + #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - -#include -#include -#include "ft-hb.h" - + FT_LOCAL_ARRAY( hb_script_t ) + af_hb_scripts[]; #endif -FT_BEGIN_HEADER - FT_Error af_shaper_get_coverage( AF_FaceGlobals globals, AF_StyleClass style_class, @@ -42,11 +39,11 @@ FT_BEGIN_HEADER void* - af_shaper_buf_create( FT_Face face ); + af_shaper_buf_create( AF_FaceGlobals globals ); void - af_shaper_buf_destroy( FT_Face face, - void* buf ); + af_shaper_buf_destroy( AF_FaceGlobals globals, + void* buf ); const char* af_shaper_get_cluster( const char* p, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h b/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h index 7a33f37a856..206232efe25 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afstyles.h @@ -4,7 +4,7 @@ * * Auto-fitter styles (specification only). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -50,36 +50,36 @@ AF_COVERAGE_ ## C ) #undef META_STYLE_LATIN -#define META_STYLE_LATIN( s, S, ds ) \ - STYLE_LATIN( s, S, c2cp, C2CP, ds, \ +#define META_STYLE_LATIN( s, S, ds ) \ + STYLE_LATIN( s, S, c2cp, C2CP, ds, \ "petite capitals from capitals", \ - PETITE_CAPITALS_FROM_CAPITALS ) \ - STYLE_LATIN( s, S, c2sc, C2SC, ds, \ + PETITE_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, c2sc, C2SC, ds, \ "small capitals from capitals", \ - SMALL_CAPITALS_FROM_CAPITALS ) \ - STYLE_LATIN( s, S, ordn, ORDN, ds, \ - "ordinals", \ - ORDINALS ) \ - STYLE_LATIN( s, S, pcap, PCAP, ds, \ - "petite capitals", \ - PETITE_CAPITALS ) \ - STYLE_LATIN( s, S, sinf, SINF, ds, \ - "scientific inferiors", \ - SCIENTIFIC_INFERIORS ) \ - STYLE_LATIN( s, S, smcp, SMCP, ds, \ - "small capitals", \ - SMALL_CAPITALS ) \ - STYLE_LATIN( s, S, subs, SUBS, ds, \ - "subscript", \ - SUBSCRIPT ) \ - STYLE_LATIN( s, S, sups, SUPS, ds, \ - "superscript", \ - SUPERSCRIPT ) \ - STYLE_LATIN( s, S, titl, TITL, ds, \ - "titling", \ - TITLING ) \ - STYLE_LATIN( s, S, dflt, DFLT, ds, \ - "default", \ + SMALL_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, ordn, ORDN, ds, \ + "ordinals", \ + ORDINALS ) \ + STYLE_LATIN( s, S, pcap, PCAP, ds, \ + "petite capitals", \ + PETITE_CAPITALS ) \ + STYLE_LATIN( s, S, sinf, SINF, ds, \ + "scientific inferiors", \ + SCIENTIFIC_INFERIORS ) \ + STYLE_LATIN( s, S, smcp, SMCP, ds, \ + "small capitals", \ + SMALL_CAPITALS ) \ + STYLE_LATIN( s, S, subs, SUBS, ds, \ + "subscript", \ + SUBSCRIPT ) \ + STYLE_LATIN( s, S, sups, SUPS, ds, \ + "superscript", \ + SUPERSCRIPT ) \ + STYLE_LATIN( s, S, titl, TITL, ds, \ + "titling", \ + TITLING ) \ + STYLE_LATIN( s, S, dflt, DFLT, ds, \ + "default", \ DEFAULT ) diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h b/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h index 27e4185e9f8..959640a12ec 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aftypes.h @@ -4,7 +4,7 @@ * * Auto-fitter types (specification only). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -406,6 +407,7 @@ extern void* af_debug_hints_; typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; + /* This is the main structure that combines everything. Autofit modules */ /* specific to writing systems derive their structures from it, for */ /* example `AF_LatinMetrics'. */ @@ -418,6 +420,8 @@ extern void* af_debug_hints_; AF_FaceGlobals globals; /* to access properties */ + FT_Hash reverse_charmap; + } AF_StyleMetricsRec; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h b/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h index b78745af74e..12fa7a27a2b 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afws-decl.h @@ -4,7 +4,7 @@ * * Auto-fitter writing system declarations (specification only). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h b/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h index c86d609a352..1752697b375 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afws-iter.h @@ -4,7 +4,7 @@ * * Auto-fitter writing systems iterator (specification only). * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.c b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.c new file mode 100644 index 00000000000..3c145d04640 --- /dev/null +++ b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.c @@ -0,0 +1,197 @@ +/**************************************************************************** + * + * ft-hb.c + * + * FreeType-HarfBuzz bridge (body). + * + * Copyright (C) 2025 by + * Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#if !defined( _WIN32 ) && !defined( _GNU_SOURCE ) +# define _GNU_SOURCE 1 /* for RTLD_DEFAULT */ +#endif + +#include +#include + +#include "afglobal.h" + +#include "ft-hb.h" + + +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + +#ifndef FT_LIBHARFBUZZ +# ifdef _WIN32 +# define FT_LIBHARFBUZZ "libharfbuzz-0.dll" +# else +# ifdef __APPLE__ +# define FT_LIBHARFBUZZ "libharfbuzz.0.dylib" +# else +# define FT_LIBHARFBUZZ "libharfbuzz.so.0" +# endif +# endif +#endif + +#ifdef _WIN32 + +# include + +#else /* !_WIN32 */ + +# include + + /* The GCC pragma suppresses the warning "ISO C forbids */ + /* assignment between function pointer and 'void *'", which */ + /* inevitably gets emitted with `-Wpedantic`; see the man */ + /* page of function `dlsym` for more information. */ +# if defined( __GNUC__ ) +# pragma GCC diagnostic push +# ifndef __cplusplus +# pragma GCC diagnostic ignored "-Wpedantic" +# endif +# endif + +#endif /* !_WIN32 */ + + + FT_LOCAL_DEF( void ) + ft_hb_funcs_init( struct AF_ModuleRec_ *af_module ) + { + FT_Memory memory = af_module->root.memory; + FT_Error error; + + ft_hb_funcs_t *funcs = NULL; + ft_hb_version_atleast_func_t version_atleast = NULL; + +#ifdef _WIN32 + HANDLE lib; +# define DLSYM( lib, name ) \ + (ft_ ## name ## _func_t)GetProcAddress( lib, #name ) +#else + void *lib; +# define DLSYM( lib, name ) \ + (ft_ ## name ## _func_t)dlsym( lib, #name ) +#endif + + + af_module->hb_funcs = NULL; + + if ( FT_NEW( funcs ) ) + return; + FT_ZERO( funcs ); + +#ifdef _WIN32 + + lib = LoadLibraryA( FT_LIBHARFBUZZ ); + if ( !lib ) + goto Fail; + version_atleast = DLSYM( lib, hb_version_atleast ); + +#else /* !_WIN32 */ + +# ifdef RTLD_DEFAULT +# define FT_RTLD_FLAGS RTLD_LAZY | RTLD_GLOBAL + lib = RTLD_DEFAULT; + version_atleast = DLSYM( lib, hb_version_atleast ); +# else +# define FT_RTLD_FLAGS RTLD_LAZY +# endif + + if ( !version_atleast ) + { + /* Load the HarfBuzz library. + * + * We never close the library, since we opened it with RTLD_GLOBAL. + * This is important for the case where we are using HarfBuzz as a + * shared library, and we want to use the symbols from the library in + * other shared libraries or clients. HarfBuzz holds onto global + * variables, and closing the library will cause them to be + * invalidated. + */ + lib = dlopen( FT_LIBHARFBUZZ, FT_RTLD_FLAGS ); + if ( !lib ) + goto Fail; + version_atleast = DLSYM( lib, hb_version_atleast ); + } + +#endif /* !_WIN32 */ + + if ( !version_atleast ) + goto Fail; + + /* Load all symbols we use. */ +#define HB_EXTERN( ret, name, args ) \ + { \ + funcs->name = DLSYM( lib, name ); \ + if ( !funcs->name ) \ + goto Fail; \ + } +#include "ft-hb-decls.h" +#undef HB_EXTERN + +#undef DLSYM + + af_module->hb_funcs = funcs; + return; + + Fail: + if ( funcs ) + FT_FREE( funcs ); + } + + + FT_LOCAL_DEF( void ) + ft_hb_funcs_done( struct AF_ModuleRec_ *af_module ) + { + FT_Memory memory = af_module->root.memory; + + + if ( af_module->hb_funcs ) + { + FT_FREE( af_module->hb_funcs ); + af_module->hb_funcs = NULL; + } + } + + + FT_LOCAL_DEF( FT_Bool ) + ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ) + { + return globals->module->hb_funcs != NULL; + } + +#ifndef _WIN32 +# if defined( __GNUC__ ) +# pragma GCC diagnostic pop +# endif +#endif + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + + FT_LOCAL_DEF( FT_Bool ) + ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ) + { + FT_UNUSED( globals ); + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + return TRUE; +#else + return FALSE; +#endif + } + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + + +/* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.h b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.h new file mode 100644 index 00000000000..95914deb8d3 --- /dev/null +++ b/src/java.desktop/share/native/libfreetype/src/autofit/ft-hb.h @@ -0,0 +1,82 @@ +/**************************************************************************** + * + * ft-hb.h + * + * FreeType-HarfBuzz bridge (specification). + * + * Copyright (C) 2025 by + * Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#ifndef FT_HB_H +#define FT_HB_H + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +# include "ft-hb-types.h" + +# ifdef FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC + +# define HB_EXTERN( ret, name, args ) \ + typedef ret (*ft_ ## name ## _func_t) args; +# include "ft-hb-decls.h" +# undef HB_EXTERN + + typedef struct ft_hb_funcs_t + { +# define HB_EXTERN( ret, name, args ) \ + ft_ ## name ## _func_t name; +# include "ft-hb-decls.h" +# undef HB_EXTERN + } ft_hb_funcs_t; + + struct AF_ModuleRec_; + + FT_LOCAL( void ) + ft_hb_funcs_init( struct AF_ModuleRec_ *af_module ); + + FT_LOCAL( void ) + ft_hb_funcs_done( struct AF_ModuleRec_ *af_module ); + +# define hb( x ) globals->module->hb_funcs->hb_ ## x + +# else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + +# define HB_EXTERN( ret, name, args ) \ + ret name args; +# include "ft-hb-decls.h" +# undef HB_EXTERN + +# define hb( x ) hb_ ## x + +# endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + struct AF_FaceGlobalsRec_; + + FT_LOCAL( FT_Bool ) + ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ); + + +FT_END_HEADER + +#endif /* FT_HB_H */ + + +/* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c b/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c index 717f7d08b35..ff0fc510503 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftadvanc.c @@ -4,7 +4,7 @@ * * Quick computation of advance widths (body). * - * Copyright (C) 2008-2024 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbase.h b/src/java.desktop/share/native/libfreetype/src/base/ftbase.h index 1d98b26dd51..66f091165fe 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbase.h +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbase.h @@ -4,7 +4,7 @@ * * Private functions used in the `base' module (specification). * - * Copyright (C) 2008-2024 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. * * This file is part of the FreeType project, and may only be used, @@ -34,7 +34,7 @@ FT_BEGIN_HEADER #ifdef FT_CONFIG_OPTION_MAC_FONTS /* MacOS resource fork cannot exceed 16MB at least for Carbon code; */ - /* see https://support.microsoft.com/en-us/kb/130437 */ + /* see https://jeffpar.github.io/kbarchive/kb/130/Q130437/ */ #define FT_MAC_RFORK_MAX_LEN 0x00FFFFFFUL diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c index d6aa5d56df8..feccdee5dd7 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c @@ -4,7 +4,7 @@ * * FreeType bbox computation (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c index 4be145679fd..2c8e44b905d 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (body). * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -876,13 +876,13 @@ #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE5(( "FT_Bitmap_Blend:\n" )); - FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", source_llx / 64, source_lly / 64, source_urx / 64, source_ury / 64, source_->width, source_->rows )); if ( target->width && target->rows ) - FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", target_llx / 64, target_lly / 64, target_urx / 64, target_ury / 64, target->width, target->rows )); @@ -890,7 +890,7 @@ FT_TRACE5(( " target bitmap: empty\n" )); if ( final_width && final_rows ) - FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %d x %d\n", + FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", final_llx / 64, final_lly / 64, final_urx / 64, final_ury / 64, final_width, final_rows )); @@ -924,7 +924,7 @@ if ( FT_LONG_MAX / target->pitch < (int)target->rows ) { - FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%u x %u)\n", final_width, final_rows )); return FT_THROW( Invalid_Argument ); } @@ -952,7 +952,7 @@ if ( FT_LONG_MAX / new_pitch < (int)final_rows ) { - FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%u x %u)\n", final_width, final_rows )); return FT_THROW( Invalid_Argument ); } diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c index 92de09ed877..7d6e12e2543 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c @@ -4,7 +4,7 @@ * * Arithmetic computations (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -38,24 +38,11 @@ #include #include - -#ifdef FT_MULFIX_ASSEMBLER -#undef FT_MulFix + /* cancel inlining macro from internal/ftcalc.h */ +#ifdef FT_MulFix +# undef FT_MulFix #endif -/* we need to emulate a 64-bit data type if a real one isn't available */ - -#ifndef FT_INT64 - - typedef struct FT_Int64_ - { - FT_UInt32 lo; - FT_UInt32 hi; - - } FT_Int64; - -#endif /* !FT_INT64 */ - /************************************************************************** * @@ -88,7 +75,7 @@ FT_EXPORT_DEF( FT_Fixed ) FT_RoundFix( FT_Fixed a ) { - return ( ADD_LONG( a, 0x8000L - ( a < 0 ) ) ) & ~0xFFFFL; + return ADD_LONG( a, 0x8000L - ( a < 0 ) ) & ~0xFFFFL; } @@ -97,7 +84,7 @@ FT_EXPORT_DEF( FT_Fixed ) FT_CeilFix( FT_Fixed a ) { - return ( ADD_LONG( a, 0xFFFFL ) ) & ~0xFFFFL; + return ADD_LONG( a, 0xFFFFL ) & ~0xFFFFL; } @@ -225,18 +212,18 @@ FT_MulFix( FT_Long a_, FT_Long b_ ) { -#ifdef FT_MULFIX_ASSEMBLER +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX - return FT_MULFIX_ASSEMBLER( (FT_Int32)a_, (FT_Int32)b_ ); + return FT_MulFix_64( a_, b_ ); #else - FT_Int64 ab = (FT_Int64)a_ * (FT_Int64)b_; + FT_Int64 ab = MUL_INT64( a_, b_ ); /* this requires arithmetic right shift of signed numbers */ - return (FT_Long)( ( ab + 0x8000L - ( ab < 0 ) ) >> 16 ); + return (FT_Long)( ( ab + 0x8000L + ( ab >> 63 ) ) >> 16 ); -#endif /* FT_MULFIX_ASSEMBLER */ +#endif /* FT_CONFIG_OPTION_INLINE_MULFIX */ } @@ -975,43 +962,36 @@ #else - FT_Int result; + FT_Int64 z1, z2; + FT_Int result; - if ( ADD_LONG( FT_ABS( in_x ), FT_ABS( out_y ) ) <= 131071L && - ADD_LONG( FT_ABS( in_y ), FT_ABS( out_x ) ) <= 131071L ) + if ( (FT_ULong)FT_ABS( in_x ) + (FT_ULong)FT_ABS( out_y ) <= 92681UL ) { - FT_Long z1 = MUL_LONG( in_x, out_y ); - FT_Long z2 = MUL_LONG( in_y, out_x ); - - - if ( z1 > z2 ) - result = +1; - else if ( z1 < z2 ) - result = -1; - else - result = 0; + z1.lo = (FT_UInt32)in_x * (FT_UInt32)out_y; + z1.hi = (FT_UInt32)( (FT_Int32)z1.lo >> 31 ); /* sign-expansion */ } - else /* products might overflow 32 bits */ - { - FT_Int64 z1, z2; - - - /* XXX: this function does not allow 64-bit arguments */ + else ft_multo64( (FT_UInt32)in_x, (FT_UInt32)out_y, &z1 ); + + if ( (FT_ULong)FT_ABS( in_y ) + (FT_ULong)FT_ABS( out_x ) <= 92681UL ) + { + z2.lo = (FT_UInt32)in_y * (FT_UInt32)out_x; + z2.hi = (FT_UInt32)( (FT_Int32)z2.lo >> 31 ); /* sign-expansion */ + } + else ft_multo64( (FT_UInt32)in_y, (FT_UInt32)out_x, &z2 ); - if ( z1.hi > z2.hi ) - result = +1; - else if ( z1.hi < z2.hi ) - result = -1; - else if ( z1.lo > z2.lo ) - result = +1; - else if ( z1.lo < z2.lo ) - result = -1; - else - result = 0; - } + if ( (FT_Int32)z1.hi > (FT_Int32)z2.hi ) + result = +1; + else if ( (FT_Int32)z1.hi < (FT_Int32)z2.hi ) + result = -1; + else if ( z1.lo > z2.lo ) + result = +1; + else if ( z1.lo < z2.lo ) + result = -1; + else + result = 0; /* XXX: only the sign of return value, +1/0/-1 must be used */ return result; @@ -1065,62 +1045,4 @@ } - FT_BASE_DEF( FT_Int32 ) - FT_MulAddFix( FT_Fixed* s, - FT_Int32* f, - FT_UInt count ) - { - FT_UInt i; - FT_Int64 temp; - - -#ifdef FT_INT64 - temp = 0; - - for ( i = 0; i < count; ++i ) - temp += (FT_Int64)s[i] * f[i]; - - return (FT_Int32)( ( temp + 0x8000 ) >> 16 ); -#else - temp.hi = 0; - temp.lo = 0; - - for ( i = 0; i < count; ++i ) - { - FT_Int64 multResult; - - FT_Int sign = 1; - FT_UInt32 carry = 0; - - FT_UInt32 scalar; - FT_UInt32 factor; - - - FT_MOVE_SIGN( FT_UInt32, s[i], scalar, sign ); - FT_MOVE_SIGN( FT_UInt32, f[i], factor, sign ); - - ft_multo64( scalar, factor, &multResult ); - - if ( sign < 0 ) - { - /* Emulated `FT_Int64` negation. */ - carry = ( multResult.lo == 0 ); - - multResult.lo = ~multResult.lo + 1; - multResult.hi = ~multResult.hi + carry; - } - - FT_Add64( &temp, &multResult, &temp ); - } - - /* Shift and round value. */ - return (FT_Int32)( ( ( temp.hi << 16 ) | ( temp.lo >> 16 ) ) - + ( 1 & ( temp.lo >> 15 ) ) ); - - -#endif /* !FT_INT64 */ - - } - - /* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcid.c b/src/java.desktop/share/native/libfreetype/src/base/ftcid.c index 4f2deb19a05..35cd0fcd2be 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftcid.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftcid.c @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information. * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c b/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c index c6bf2a3cd1a..90b02b7d2de 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftcolor.c @@ -4,7 +4,7 @@ * * FreeType's glyph color management (body). * - * Copyright (C) 2018-2024 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -56,9 +56,7 @@ FT_Color* *apalette ) { FT_Error error; - - TT_Face ttface; - SFNT_Service sfnt; + TT_Face ttface = (TT_Face)face; if ( !face ) @@ -72,14 +70,17 @@ return FT_Err_Ok; } - ttface = (TT_Face)face; - sfnt = (SFNT_Service)ttface->sfnt; + if ( palette_index != ttface->palette_index ) + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; - error = sfnt->set_palette( ttface, palette_index ); - if ( error ) - return error; - ttface->palette_index = palette_index; + error = sfnt->set_palette( ttface, palette_index ); + if ( error ) + return error; + + ttface->palette_index = palette_index; + } if ( apalette ) *apalette = ttface->palette; diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c index 902a5dc8bbc..7f54e759b16 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftdbgmem.c @@ -4,7 +4,7 @@ * * Memory debugger (body). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -139,7 +139,6 @@ } FT_MemTableRec; -#define FT_MEM_SIZE_MIN 7 #define FT_MEM_SIZE_MAX 13845163 #define FT_FILENAME( x ) ( (x) ? (x) : "unknown file" ) diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c b/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c index 11307eaace4..c615f29e521 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftdebug.c @@ -4,7 +4,7 @@ * * Debugging and logging component (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -64,7 +64,7 @@ * with the actual log message if set to true. * * 5. The flag `ft_timestamp_flag` prints time along with the actual log - * message if set to ture. + * message if set to true. * * 6. `ft_have_newline_char` is used to differentiate between a log * message with and without a trailing newline character. diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c b/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c index 77b4089e7e2..7f4f14ffdb0 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftfntfmt.c @@ -4,7 +4,7 @@ * * FreeType utility file for font formats (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c b/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c index 1565c3b7e25..3a95752ffaa 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftfstype.c @@ -4,7 +4,7 @@ * * FreeType utility file to access FSType data (body). * - * Copyright (C) 2008-2024 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c b/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c index c63d30e978c..2202240b57e 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftgasp.c @@ -4,7 +4,7 @@ * * Access of TrueType's `gasp' table (body). * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c b/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c index 484d98f1722..47781bc4d5c 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftgloadr.c @@ -4,7 +4,7 @@ * * The FreeType glyph loader (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c b/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c index 1b5849f99af..75babb1aa56 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftglyph.c @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/fthash.c b/src/java.desktop/share/native/libfreetype/src/base/fthash.c index 313bbbb4b27..ab248ace8bd 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/fthash.c +++ b/src/java.desktop/share/native/libfreetype/src/base/fthash.c @@ -41,6 +41,7 @@ #include #include +#include #define INITIAL_HT_SIZE 241 @@ -233,7 +234,8 @@ hash_insert( FT_Hashkey key, size_t data, FT_Hash hash, - FT_Memory memory ) + FT_Memory memory, + FT_Bool overwrite ) { FT_Hashnode nn; FT_Hashnode* bp = hash_bucket( key, hash ); @@ -259,7 +261,7 @@ hash->used++; } - else + else if ( overwrite ) nn->data = data; Exit: @@ -278,7 +280,7 @@ hk.str = key; - return hash_insert( hk, data, hash, memory ); + return hash_insert( hk, data, hash, memory, TRUE ); } @@ -293,7 +295,37 @@ hk.num = num; - return hash_insert( hk, data, hash, memory ); + return hash_insert( hk, data, hash, memory, TRUE ); + } + + + FT_Error + ft_hash_str_insert_no_overwrite( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.str = key; + + return hash_insert( hk, data, hash, memory, FALSE ); + } + + + FT_Error + ft_hash_num_insert_no_overwrite( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.num = num; + + return hash_insert( hk, data, hash, memory, FALSE ); } @@ -335,4 +367,68 @@ } + FT_Bool + ft_hash_num_iterator( FT_UInt *idx, + FT_Int *key, + size_t *value, + FT_Hash hash ) + { + FT_Hashnode nn = NULL; + + + while ( 1 ) + { + if ( *idx >= hash->size ) + return 0; + + nn = hash->table[*idx]; + if ( nn ) + break; + + (*idx)++; + } + + if ( key ) + *key = nn->key.num; + if ( value ) + *value = nn->data; + + (*idx)++; + + return 1; + } + + + FT_Bool + ft_hash_str_iterator( FT_UInt *idx, + const char* *key, + size_t *value, + FT_Hash hash ) + { + FT_Hashnode nn = NULL; + + + while ( 1 ) + { + if ( *idx >= hash->size ) + return 0; + + nn = hash->table[*idx]; + if ( nn ) + break; + + (*idx)++; + } + + if ( key ) + *key = nn->key.str; + if ( value ) + *value = nn->data; + + (*idx)++; + + return 1; + } + + /* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftinit.c b/src/java.desktop/share/native/libfreetype/src/base/ftinit.c index 9a6c00e13ef..37d7f87bcb9 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftinit.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftinit.c @@ -4,7 +4,7 @@ * * FreeType initialization layer (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c b/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c index 1e69d4da70f..d026da8b012 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftlcdfil.c @@ -4,7 +4,7 @@ * * FreeType API for color filtering of subpixel bitmap glyphs (body). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c index e8e35627b50..37d97be1838 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftmac.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftmac.c @@ -8,7 +8,7 @@ * This file is for Mac OS X only; see builds/mac/ftoldmac.c for * classic platforms built by MPW. * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c index cc4ca22fba3..9e67001406c 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftmm.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftmm.c @@ -4,7 +4,7 @@ * * Multiple Master font support (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -292,6 +292,9 @@ if ( num_coords && !coords ) return FT_THROW( Invalid_Argument ); + if ( !num_coords && !FT_IS_VARIATION( face ) ) + return FT_Err_Ok; /* nothing to be done */ + error = ft_face_get_mm_service( face, &service_mm ); if ( !error ) { @@ -299,15 +302,21 @@ if ( service_mm->set_var_design ) error = service_mm->set_var_design( face, num_coords, coords ); - if ( !error || error == -1 ) + if ( !error || error == -1 || error == -2 ) { FT_Bool is_variation_old = FT_IS_VARIATION( face ); - if ( num_coords ) - face->face_flags |= FT_FACE_FLAG_VARIATION; - else - face->face_flags &= ~FT_FACE_FLAG_VARIATION; + if ( error != -1 ) + { + if ( error == -2 ) /* -2 means is_variable. */ + { + face->face_flags |= FT_FACE_FLAG_VARIATION; + error = FT_Err_Ok; + } + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } if ( service_mm->construct_ps_name ) { @@ -474,15 +483,21 @@ if ( service_mm->set_mm_blend ) error = service_mm->set_mm_blend( face, num_coords, coords ); - if ( !error || error == -1 ) + if ( !error || error == -1 || error == -2 ) { FT_Bool is_variation_old = FT_IS_VARIATION( face ); - if ( num_coords ) - face->face_flags |= FT_FACE_FLAG_VARIATION; - else - face->face_flags &= ~FT_FACE_FLAG_VARIATION; + if ( error != -1 ) + { + if ( error == -2 ) /* -2 means is_variable. */ + { + face->face_flags |= FT_FACE_FLAG_VARIATION; + error = FT_Err_Ok; + } + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } if ( service_mm->construct_ps_name ) { diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c index 9b97820c379..cced4fed06b 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c @@ -4,7 +4,7 @@ * * The FreeType private base classes (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -905,7 +905,6 @@ FT_Library library; FT_Bool autohint = FALSE; FT_Module hinter; - TT_Face ttface = (TT_Face)face; if ( !face || !face->size || !face->glyph ) @@ -983,6 +982,7 @@ { FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); FT_Bool is_light_type1; + TT_Face ttface = (TT_Face)face; /* only the new Adobe engine (for both CFF and Type 1) is `light'; */ @@ -994,8 +994,7 @@ /* the check for `num_locations' assures that we actually */ /* test for instructions in a TTF and not in a CFF-based OTF */ /* */ - /* since `maxSizeOfInstructions' might be unreliable, we */ - /* check the size of the `fpgm' and `prep' tables, too -- */ + /* we check the size of the `fpgm' and `prep' tables, too -- */ /* the assumption is that there don't exist real TTFs where */ /* both `fpgm' and `prep' tables are missing */ if ( ( mode == FT_RENDER_MODE_LIGHT && @@ -1003,9 +1002,8 @@ !is_light_type1 ) ) || ( FT_IS_SFNT( face ) && ttface->num_locations && - ttface->max_profile.maxSizeOfInstructions == 0 && ttface->font_program_size == 0 && - ttface->cvt_program_size == 0 ) ) + ttface->cvt_program_size <= 7 ) ) autohint = TRUE; } } @@ -1172,9 +1170,9 @@ } #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n", + FT_TRACE5(( "FT_Load_Glyph: index %u, flags 0x%x\n", glyph_index, load_flags )); - FT_TRACE5(( " bitmap %dx%d %s, %s (mode %d)\n", + FT_TRACE5(( " bitmap %ux%u %s, %s (mode %d)\n", slot->bitmap.width, slot->bitmap.rows, slot->outline.points ? @@ -1253,14 +1251,14 @@ FT_Driver driver = (FT_Driver)driver_; - /* finalize client-specific data */ - if ( size->generic.finalizer ) - size->generic.finalizer( size ); - /* finalize format-specific stuff */ if ( driver->clazz->done_size ) driver->clazz->done_size( size ); + /* finalize client-specific data */ + if ( size->generic.finalizer ) + size->generic.finalizer( size ); + FT_FREE( size->internal ); FT_FREE( size ); } @@ -1322,10 +1320,6 @@ driver ); face->size = NULL; - /* now discard client data */ - if ( face->generic.finalizer ) - face->generic.finalizer( face ); - /* discard charmaps */ destroy_charmaps( face, memory ); @@ -1340,6 +1334,10 @@ face->stream = NULL; + /* now discard client data */ + if ( face->generic.finalizer ) + face->generic.finalizer( face ); + /* get rid of it */ if ( face->internal ) { @@ -1359,21 +1357,9 @@ } - /************************************************************************** - * - * @Function: - * find_unicode_charmap - * - * @Description: - * This function finds a Unicode charmap, if there is one. - * And if there is more than one, it tries to favour the more - * extensive one, i.e., one that supports UCS-4 against those which - * are limited to the BMP (said UCS-2 encoding.) - * - * This function is called from open_face() (just below), and also - * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). - */ - static FT_Error + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) find_unicode_charmap( FT_Face face ) { FT_CharMap* first; @@ -2125,7 +2111,7 @@ if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len ) goto Exit2; - FT_TRACE3(( " Load POST fragment #%d (%ld byte) to buffer" + FT_TRACE3(( " Load POST fragment #%d (%lu byte) to buffer" " %p + 0x%08lx\n", i, rlen, (void*)pfb_data, pfb_pos )); @@ -2398,7 +2384,7 @@ is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i ); if ( is_darwin_vfs && vfs_rfork_has_no_font ) { - FT_TRACE3(( "Skip rule %d: darwin vfs resource fork" + FT_TRACE3(( "Skip rule %u: darwin vfs resource fork" " is already checked and" " no font is found\n", i )); @@ -2407,7 +2393,7 @@ if ( errors[i] ) { - FT_TRACE3(( "Error 0x%x has occurred in rule %d\n", + FT_TRACE3(( "Error 0x%x has occurred in rule %u\n", errors[i], i )); continue; } @@ -2415,7 +2401,7 @@ args2.flags = FT_OPEN_PATHNAME; args2.pathname = file_names[i] ? file_names[i] : args->pathname; - FT_TRACE3(( "Try rule %d: %s (offset=%ld) ...", + FT_TRACE3(( "Try rule %u: %s (offset=%ld) ...", i, args2.pathname, offsets[i] )); error = FT_Stream_New( library, &args2, &stream2 ); @@ -5044,9 +5030,9 @@ static void Destroy_Module( FT_Module module ) { - FT_Memory memory = module->memory; - FT_Module_Class* clazz = module->clazz; - FT_Library library = module->library; + const FT_Module_Class* clazz = module->clazz; + FT_Library library = module->library; + FT_Memory memory = module->memory; if ( library && library->auto_hinter == module ) @@ -5125,9 +5111,9 @@ goto Exit; /* base initialization */ + module->clazz = clazz; module->library = library; module->memory = memory; - module->clazz = (FT_Module_Class*)clazz; /* check whether the module is a renderer - this must be performed */ /* before the normal module initialization */ diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c index ef699b3c7cd..8a15b03eb83 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c @@ -4,7 +4,7 @@ * * FreeType outline management (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c b/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c index 2055757e023..664bc34deea 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftpatent.c @@ -5,7 +5,7 @@ * FreeType API for checking patented TrueType bytecode instructions * (body). Obsolete, retained for backward compatibility. * - * Copyright (C) 2007-2024 by + * Copyright (C) 2007-2025 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c b/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c index 37a6cee6cc9..0631cd63f62 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftpsprop.c @@ -5,7 +5,7 @@ * Get and set properties of PostScript drivers (body). * See `ftdriver.h' for available properties. * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c b/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c index dc9b043d8bb..1e241f4f95b 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftrfork.c @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (body). * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * Masatake YAMATO and Redhat K.K. * * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are @@ -269,14 +269,8 @@ * According to Inside Macintosh: More Macintosh Toolbox, * "Resource IDs" (1-46), there are some reserved IDs. * However, FreeType2 is not a font synthesizer, no need - * to check the acceptable resource ID. + * to check the acceptable resource ID or its attributes. */ - if ( temp < 0 ) - { - error = FT_THROW( Invalid_Table ); - goto Exit; - } - ref[j].offset = temp & 0xFFFFFFL; FT_TRACE3(( " [%d]:" diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c b/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c index f7231fd61cc..34a67a148fc 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftsnames.c @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c index 66722246128..c04a0506def 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftstream.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftstream.c @@ -4,7 +4,7 @@ * * I/O stream support (body). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -242,7 +242,7 @@ FT_ULong read_bytes; - FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count )); + FT_TRACE7(( "FT_Stream_EnterFrame: %lu bytes\n", count )); /* check for nested frame access */ FT_ASSERT( stream && stream->cursor == 0 ); diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c index 64f46ce43e7..591f18eaa83 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c @@ -4,7 +4,7 @@ * * FreeType path stroker (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1070,7 +1070,7 @@ if ( theta == FT_ANGLE_PI2 ) theta = -rotate; - phi = stroker->angle_in + theta + rotate; + phi = stroker->angle_in + theta + rotate; FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta ); @@ -1371,7 +1371,7 @@ arc[1] = *control; arc[2] = stroker->center; - while ( arc >= bez_stack ) + do { FT_Angle angle_in, angle_out; @@ -1524,10 +1524,12 @@ } } - arc -= 2; - stroker->angle_in = angle_out; - } + + if ( arc == bez_stack ) + break; + arc -= 2; + } while ( 1 ); stroker->center = *to; stroker->line_length = 0; @@ -1577,7 +1579,7 @@ arc[2] = *control1; arc[3] = stroker->center; - while ( arc >= bez_stack ) + do { FT_Angle angle_in, angle_mid, angle_out; @@ -1741,10 +1743,12 @@ } } - arc -= 3; - stroker->angle_in = angle_out; - } + + if ( arc == bez_stack ) + break; + arc -= 3; + } while ( 1 ); stroker->center = *to; stroker->line_length = 0; diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c index ec05bce33a9..08bc1742202 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftsynth.c @@ -4,7 +4,7 @@ * * FreeType synthesizing code for emboldening and slanting (body). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -141,7 +141,7 @@ /* * XXX: overflow check for 16-bit system, for compatibility * with FT_GlyphSlot_Embolden() since FreeType 2.1.10. - * unfortunately, this function return no informations + * unfortunately, this function returns no information * about the cause of error. */ if ( ( ystr >> 6 ) > FT_INT_MAX || ( ystr >> 6 ) < FT_INT_MIN ) diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c index eee3642334f..186119d5581 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftsystem.c @@ -4,7 +4,7 @@ * * ANSI-specific FreeType low-level system interface (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -280,7 +280,7 @@ stream->close = ft_ansi_stream_close; FT_TRACE1(( "FT_Stream_Open:" )); - FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", + FT_TRACE1(( " opened `%s' (%lu bytes) successfully\n", filepathname, stream->size )); return FT_Err_Ok; diff --git a/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c b/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c index 4b1aced1cba..29eff639c51 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c +++ b/src/java.desktop/share/native/libfreetype/src/base/fttrigon.c @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (body). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/fttype1.c b/src/java.desktop/share/native/libfreetype/src/base/fttype1.c index cedf7c40505..77978df674d 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/fttype1.c +++ b/src/java.desktop/share/native/libfreetype/src/base/fttype1.c @@ -4,7 +4,7 @@ * * FreeType utility file for PS names support (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftutil.c b/src/java.desktop/share/native/libfreetype/src/base/ftutil.c index b13512f8704..0b7382627c5 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftutil.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftutil.c @@ -4,7 +4,7 @@ * * FreeType utility file for memory and list management (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c index ea5f8ed2885..cb69abdb90f 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.c @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h index 1dd8700cd8b..60e16d94875 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffcmap.h @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c index f6ebdb3810a..0079ddd1950 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c @@ -4,7 +4,7 @@ * * OpenType font driver implementation (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. * * This file is part of the FreeType project, and may only be used, @@ -121,7 +121,20 @@ kerning->y = 0; if ( sfnt ) - kerning->x = sfnt->get_kerning( cffface, left_glyph, right_glyph ); + { + /* Use 'kern' table if available since that can be faster; otherwise */ + /* use GPOS kerning pairs if available. */ + if ( cffface->kern_avail_bits ) + kerning->x = sfnt->get_kerning( cffface, + left_glyph, + right_glyph ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + else if ( cffface->num_gpos_lookups_kerning ) + kerning->x = sfnt->get_gpos_kerning( cffface, + left_glyph, + right_glyph ); +#endif + } return FT_Err_Ok; } @@ -168,25 +181,7 @@ CFF_Size cffsize = (CFF_Size)size; - if ( !cffslot ) - return FT_THROW( Invalid_Slot_Handle ); - - FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index )); - - /* check whether we want a scaled outline or bitmap */ - if ( !cffsize ) - load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; - - /* reset the size object if necessary */ - if ( load_flags & FT_LOAD_NO_SCALE ) - size = NULL; - - if ( size ) - { - /* these two objects must have the same parent */ - if ( size->face != slot->face ) - return FT_THROW( Invalid_Face_Handle ); - } + FT_TRACE1(( "cff_glyph_load: glyph index %u\n", glyph_index )); /* now load the glyph outline if necessary */ error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags ); @@ -205,105 +200,70 @@ FT_Int32 flags, FT_Fixed* advances ) { - FT_UInt nn; - FT_Error error = FT_Err_Ok; - FT_GlyphSlot slot = face->glyph; + CFF_Face cffface = (CFF_Face)face; + FT_Bool horz; + FT_UInt nn; - if ( FT_IS_SFNT( face ) ) + if ( !FT_IS_SFNT( face ) ) + return FT_THROW( Unimplemented_Feature ); + + horz = !( flags & FT_LOAD_VERTICAL_LAYOUT ); + + if ( horz ) { /* OpenType 1.7 mandates that the data from `hmtx' table be used; */ /* it is no longer necessary that those values are identical to */ /* the values in the `CFF' table */ + if ( !cffface->horizontal.number_Of_HMetrics ) + return FT_THROW( Unimplemented_Feature ); - CFF_Face cffface = (CFF_Face)face; - FT_Short dummy; - - - if ( flags & FT_LOAD_VERTICAL_LAYOUT ) - { #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - /* no fast retrieval for blended MM fonts without VVAR table */ - if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && - !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) - return FT_THROW( Unimplemented_Feature ); + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); #endif + } + else /* vertical */ + { + /* check whether we have data from the `vmtx' table at all; */ + /* otherwise we extract the info from the CFF glyphstrings */ + /* (instead of synthesizing a global value using the `OS/2' */ + /* table) */ + if ( !cffface->vertical_info ) + return FT_THROW( Unimplemented_Feature ); - /* check whether we have data from the `vmtx' table at all; */ - /* otherwise we extract the info from the CFF glyphstrings */ - /* (instead of synthesizing a global value using the `OS/2' */ - /* table) */ - if ( !cffface->vertical_info ) - goto Missing_Table; - - for ( nn = 0; nn < count; nn++ ) - { - FT_UShort ah; - - - ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, - 1, - start + nn, - &dummy, - &ah ); - - FT_TRACE5(( " idx %d: advance height %d font unit%s\n", - start + nn, - ah, - ah == 1 ? "" : "s" )); - advances[nn] = ah; - } - } - else - { #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - /* no fast retrieval for blended MM fonts without HVAR table */ - if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && - !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) - return FT_THROW( Unimplemented_Feature ); + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); #endif - - /* check whether we have data from the `hmtx' table at all */ - if ( !cffface->horizontal.number_Of_HMetrics ) - goto Missing_Table; - - for ( nn = 0; nn < count; nn++ ) - { - FT_UShort aw; - - - ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, - 0, - start + nn, - &dummy, - &aw ); - - FT_TRACE5(( " idx %d: advance width %d font unit%s\n", - start + nn, - aw, - aw == 1 ? "" : "s" )); - advances[nn] = aw; - } - } - - return error; } - Missing_Table: - flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; - + /* proceed to fast advances */ for ( nn = 0; nn < count; nn++ ) { - error = cff_glyph_load( slot, face->size, start + nn, flags ); - if ( error ) - break; + FT_UShort aw; + FT_Short dummy; - advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) - ? slot->linearVertAdvance - : slot->linearHoriAdvance; + + ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, + !horz, + start + nn, + &dummy, + &aw ); + + FT_TRACE5(( " idx %u: advance %s %d font unit%s\n", + start + nn, + horz ? "width" : "height", + aw, + aw == 1 ? "" : "s" )); + advances[nn] = aw; } - return error; + return FT_Err_Ok; } diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h index fd5bc37ecd4..52a1e727a6a 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.h @@ -4,7 +4,7 @@ * * High-level OpenType driver interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h b/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h index 128adc3b716..7491886c7be 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cfferrs.h @@ -4,7 +4,7 @@ * * CFF error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c index cbb071abdfe..e8bab3c1e33 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -238,24 +238,12 @@ else if ( glyph_index >= cff->num_glyphs ) return FT_THROW( Invalid_Argument ); - if ( load_flags & FT_LOAD_NO_RECURSE ) - load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; - - glyph->x_scale = 0x10000L; - glyph->y_scale = 0x10000L; - if ( size ) - { - glyph->x_scale = size->root.metrics.x_scale; - glyph->y_scale = size->root.metrics.y_scale; - } - #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* try to load embedded bitmap if any */ /* */ /* XXX: The convention should be emphasized in */ /* the documents because it can be confusing. */ - if ( size ) { CFF_Face cff_face = (CFF_Face)size->root.face; SFNT_Service sfnt = (SFNT_Service)cff_face->sfnt; @@ -284,9 +272,6 @@ FT_Short dummy; - glyph->root.outline.n_points = 0; - glyph->root.outline.n_contours = 0; - glyph->root.metrics.width = (FT_Pos)metrics.width * 64; glyph->root.metrics.height = (FT_Pos)metrics.height * 64; @@ -423,6 +408,25 @@ #endif /* FT_CONFIG_OPTION_SVG */ + /* top-level code ensures that FT_LOAD_NO_HINTING is set */ + /* if FT_LOAD_NO_SCALE is active */ + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); + + glyph->hint = hinting; + glyph->scaled = scaled; + + if ( scaled ) + { + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + } + else + { + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + } + /* if we have a CID subfont, use its matrix (which has already */ /* been multiplied with the root matrix) */ @@ -457,18 +461,6 @@ font_offset = cff->top_font.font_dict.font_offset; } - glyph->root.outline.n_points = 0; - glyph->root.outline.n_contours = 0; - - /* top-level code ensures that FT_LOAD_NO_HINTING is set */ - /* if FT_LOAD_NO_SCALE is active */ - hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); - scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); - - glyph->hint = hinting; - glyph->scaled = scaled; - glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */ - { #ifdef CFF_CONFIG_OPTION_OLD_ENGINE PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); @@ -602,10 +594,8 @@ { /* Now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ - /* bearing the yMax. */ - - /* For composite glyphs, return only left side bearing and */ - /* advance width. */ + /* bearing the yMax. For composite glyphs, return only */ + /* left side bearing and advance width. */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = glyph->root.internal; @@ -624,6 +614,12 @@ FT_Bool has_vertical_info; + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + + glyph->root.outline.flags = FT_OUTLINE_REVERSE_FILL; + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; + if ( face->horizontal.number_Of_HMetrics ) { FT_Short horiBearingX = 0; @@ -677,14 +673,6 @@ glyph->root.linearVertAdvance = metrics->vertAdvance; - glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; - - glyph->root.outline.flags = 0; - if ( size && size->root.metrics.y_ppem < 24 ) - glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; - - glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; - /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || font_matrix.xy != 0 || font_matrix.yx != 0 ) @@ -707,7 +695,7 @@ metrics->vertAdvance += font_offset.y; } - if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) + if ( scaled || force_scaling ) { /* scale the outline and the metrics */ FT_Int n; diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h index 346d4b11c31..662bb7cff53 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c index 979fd45f6ca..326f885056f 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c @@ -4,7 +4,7 @@ * * OpenType and CFF data/program tables loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -442,7 +442,7 @@ if ( cur_offset != 0 ) { FT_TRACE0(( "cff_index_get_pointers:" - " invalid first offset value %ld set to zero\n", + " invalid first offset value %lu set to zero\n", cur_offset )); cur_offset = 0; } @@ -559,8 +559,8 @@ idx->data_offset > stream->size - off2 + 1 ) { FT_ERROR(( "cff_index_access_element:" - " offset to next entry (%ld)" - " exceeds the end of stream (%ld)\n", + " offset to next entry (%lu)" + " exceeds the end of stream (%lu)\n", off2, stream->size - idx->data_offset + 1 )); off2 = stream->size - idx->data_offset + 1; } @@ -982,7 +982,7 @@ if ( glyph_sid > 0xFFFFL - nleft ) { FT_ERROR(( "cff_charset_load: invalid SID range trimmed" - " nleft=%d -> %ld\n", nleft, 0xFFFFL - glyph_sid )); + " nleft=%u -> %ld\n", nleft, 0xFFFFL - glyph_sid )); nleft = ( FT_UInt )( 0xFFFFL - glyph_sid ); } @@ -1315,7 +1315,7 @@ if ( numOperands > count ) { - FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d argument%s\n", + FT_TRACE4(( " cff_blend_doBlend: Stack underflow %u argument%s\n", count, count == 1 ? "" : "s" )); @@ -1466,7 +1466,7 @@ if ( master == 0 ) { blend->BV[master] = FT_FIXED_ONE; - FT_TRACE4(( " build blend vector len %d\n", len )); + FT_TRACE4(( " build blend vector len %u\n", len )); FT_TRACE4(( " [ %f ", blend->BV[master] / 65536.0 )); continue; } @@ -2341,7 +2341,7 @@ if ( face_index > 0 && subfont_index >= font->name_index.count ) { FT_ERROR(( "cff_font_load:" - " invalid subfont index for pure CFF font (%d)\n", + " invalid subfont index for pure CFF font (%u)\n", subfont_index )); error = FT_THROW( Invalid_Argument ); goto Exit; diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h index 02209245421..fdc132c8f3f 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.h @@ -4,7 +4,7 @@ * * OpenType & CFF data/program tables loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c index 7c6713739a1..1aeb908f4a1 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c @@ -4,7 +4,7 @@ * * OpenType objects manager (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -537,8 +537,8 @@ sfnt_format = 1; - /* now, the font can be either an OpenType/CFF font, or an SVG CEF */ - /* font; in the latter case it doesn't have a `head' table */ + /* the font may be OpenType/CFF, SVG CEF, or sfnt/CFF; a `head' table */ + /* implies OpenType/CFF, otherwise just look for an optional cmap */ error = face->goto_table( face, TTAG_head, stream, 0 ); if ( !error ) { @@ -554,7 +554,9 @@ { /* load the `cmap' table explicitly */ error = sfnt->load_cmap( face, stream ); - if ( error ) + + /* this may fail because CID-keyed fonts don't have a cmap */ + if ( FT_ERR_NEQ( error, Table_Missing ) && FT_ERR_NEQ( error, Ok ) ) goto Exit; } @@ -651,7 +653,7 @@ { s = cff_index_get_sid_string( cff, idx ); if ( s ) - FT_TRACE4(( " %5d %s\n", idx, s )); + FT_TRACE4(( " %5u %s\n", idx, s )); } /* In Multiple Master CFFs, two SIDs hold the Normalize Design */ @@ -666,7 +668,7 @@ FT_PtrDist l; - FT_TRACE4(( " %5d ", idx + 390 )); + FT_TRACE4(( " %5u ", idx + 390 )); for ( l = 0; l < s1len; l++ ) FT_TRACE4(( "%c", s1[l] )); FT_TRACE4(( "\n" )); @@ -681,7 +683,7 @@ FT_PtrDist l; - FT_TRACE4(( " %5d ", cff->num_strings + 390 )); + FT_TRACE4(( " %5u ", cff->num_strings + 390 )); for ( l = 0; l < s1len; l++ ) FT_TRACE4(( "%c", s1[l] )); FT_TRACE4(( "\n" )); diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h index 91ad83b1cd0..982dcd64dd0 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.h @@ -4,7 +4,7 @@ * * OpenType objects manager (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c index 92a69c3b516..864b2490b3b 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.c @@ -4,7 +4,7 @@ * * CFF token stream parser (body) * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -892,7 +892,7 @@ dict->cid_supplement )); error = FT_Err_Ok; - FT_TRACE4(( " %d %d %ld\n", + FT_TRACE4(( " %u %u %ld\n", dict->cid_registry, dict->cid_ordering, dict->cid_supplement )); @@ -929,7 +929,7 @@ priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ ); - FT_TRACE4(( " %d\n", priv->vsindex )); + FT_TRACE4(( " %u\n", priv->vsindex )); error = FT_Err_Ok; @@ -979,7 +979,7 @@ goto Exit; } - FT_TRACE4(( " %d value%s blended\n", + FT_TRACE4(( " %u value%s blended\n", numBlends, numBlends == 1 ? "" : "s" )); @@ -1014,7 +1014,7 @@ if ( dict->maxstack < CFF2_DEFAULT_STACK ) dict->maxstack = CFF2_DEFAULT_STACK; - FT_TRACE4(( " %d\n", dict->maxstack )); + FT_TRACE4(( " %u\n", dict->maxstack )); Exit: return error; diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h index ca6b18af6aa..47cceb1a4a0 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffparse.h @@ -4,7 +4,7 @@ * * CFF token stream parser (specification) * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h b/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h index da45faa7f4e..cc5aaa2867a 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h +++ b/src/java.desktop/share/native/libfreetype/src/cff/cfftoken.h @@ -4,7 +4,7 @@ * * CFF token definitions (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h b/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h index c439a8c4a0b..1591979d370 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/ciderrs.h @@ -4,7 +4,7 @@ * * CID error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c index 7b571322d45..249ede5757d 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 Glyph Loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -103,20 +103,20 @@ if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) || ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) ) { - FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n", + FT_TRACE1(( "cid_load_glyph: fail for glyph index %u:\n", glyph_index )); - FT_TRACE1(( " FD number %ld is the maximum\n", + FT_TRACE1(( " FD number %lu is the maximum\n", fd_select )); - FT_TRACE1(( " integer fitting into %d byte%s\n", + FT_TRACE1(( " integer fitting into %u byte%s\n", cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" )); } else { - FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n", glyph_index )); - FT_TRACE0(( " FD number %ld is larger\n", + FT_TRACE0(( " FD number %lu is larger\n", fd_select )); - FT_TRACE0(( " than number of dictionaries (%d)\n", + FT_TRACE0(( " than number of dictionaries (%u)\n", cid->num_dicts )); } @@ -125,7 +125,7 @@ } else if ( off2 > stream->size ) { - FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n", glyph_index )); FT_TRACE0(( " end of the glyph data\n" )); FT_TRACE0(( " is beyond the data stream\n" )); @@ -135,7 +135,7 @@ } else if ( off1 > off2 ) { - FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n", + FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n", glyph_index )); FT_TRACE0(( " the end position of glyph data\n" )); FT_TRACE0(( " is set before the start position\n" )); @@ -252,8 +252,8 @@ cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0; if ( cs_offset > glyph_length ) { - FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, " - "offset to the charstring is beyond glyph length\n", + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%u," + " offset to the charstring is beyond glyph length\n", glyph_index )); error = FT_THROW( Invalid_Offset ); goto Exit; @@ -452,16 +452,12 @@ glyph->x_scale = cidsize->metrics.x_scale; glyph->y_scale = cidsize->metrics.y_scale; - cidglyph->outline.n_points = 0; - cidglyph->outline.n_contours = 0; - hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 && ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); glyph->hint = hinting; glyph->scaled = scaled; - cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; error = psaux->t1_decoder_funcs->init( &decoder, cidglyph->face, @@ -501,12 +497,8 @@ /* now set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ - /* bearing the yMax */ - cidglyph->outline.flags &= FT_OUTLINE_OWNER; - cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; - - /* for composite glyphs, return only left side bearing and */ - /* advance width */ + /* bearing the yMax; for composite glyphs, return only */ + /* left side bearing and advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = cidglyph->internal; @@ -527,6 +519,13 @@ FT_Glyph_Metrics* metrics = &cidglyph->metrics; + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + cidglyph->outline.flags &= FT_OUTLINE_OWNER; + cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + if ( cidsize->metrics.y_ppem < 24 ) + cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + /* copy the _unscaled_ advance width */ metrics->horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); @@ -539,11 +538,6 @@ face->cid.font_bbox.yMin ) >> 16; cidglyph->linearVertAdvance = metrics->vertAdvance; - cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; - - if ( cidsize->metrics.y_ppem < 24 ) - cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || font_matrix.xy != 0 || font_matrix.yx != 0 ) diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h index 9fdc9db5892..cef96073ded 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c index 722f5a34ddf..bb1bf13e221 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.h b/src/java.desktop/share/native/libfreetype/src/cid/cidload.h index 7f030b32df7..659dd0e378c 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c index 8d337c41128..634bbf2f135 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.c @@ -4,7 +4,7 @@ * * CID objects manager (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h index d371cbe9954..800268efa2f 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidobjs.h @@ -4,7 +4,7 @@ * * CID objects manager (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c index 73a3ade893b..4d1ba335960 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h index 0f5baddcb92..6ae2e542394 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidparse.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c index 4be8a5c00d5..a3a587c57bf 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.c @@ -4,7 +4,7 @@ * * CID driver interface (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h index 7ddce431c5b..55d0b8a0d9b 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidriver.h @@ -4,7 +4,7 @@ * * High-level CID driver interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h b/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h index 160897d1447..25ba74fed94 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidtoken.h @@ -4,7 +4,7 @@ * * CID token definitions (specification only). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c index e2f6a8e5adb..b813efde4eb 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.c @@ -4,7 +4,7 @@ * * AFM parser (body). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h index b7766372821..add8597717d 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/afmparse.h @@ -4,7 +4,7 @@ * * AFM parser (specification). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c index 9556e11a586..17bdd23c7d4 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.c @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (body). * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -2141,7 +2141,7 @@ decoder->locals_bias ); - FT_TRACE4(( " callsubr (idx %d, entering level %td)\n", + FT_TRACE4(( " callsubr (idx %u, entering level %td)\n", idx, zone - decoder->zones + 1 )); @@ -2185,7 +2185,7 @@ decoder->globals_bias ); - FT_TRACE4(( " callgsubr (idx %d, entering level %td)\n", + FT_TRACE4(( " callgsubr (idx %u, entering level %td)\n", idx, zone - decoder->zones + 1 )); diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h index 038f7235c3d..e72ec043baa 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/cffdecode.h @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (specification). * - * Copyright (C) 2017-2024 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h b/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h index 18428c40d5a..0d7fe2b6121 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxerr.h @@ -4,7 +4,7 @@ * * PS auxiliary module error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c index 6826f9d8d3e..942804190c5 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.c @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (body). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h index 82d7e348af8..4a5ebc1b607 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psauxmod.h @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (specification). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -46,9 +46,6 @@ FT_BEGIN_HEADER const CFF_Decoder_FuncsRec cff_decoder_funcs; - FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class; - - FT_DECLARE_MODULE( psaux_module_class ) diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c index 56c0ecd1d7f..4567d3f3c06 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.c @@ -4,7 +4,7 @@ * * Some convenience conversions (body). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h index 91fcd15a1c9..63735af411f 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psconv.h @@ -4,7 +4,7 @@ * * Some convenience conversions (specification). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c index 7572e225e37..7e3475e6f58 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c @@ -618,7 +618,7 @@ /* Our copy of it does not change that requirement. */ cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 ); - charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack ); + charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack ); /* catch errors so far */ if ( *error ) diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c index eca465f009e..8159fd6ef15 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.c @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -460,6 +460,9 @@ case '%': skip_comment( &cur, limit ); break; + + default: + break; } } @@ -1145,7 +1148,7 @@ FT_ERROR(( "ps_parser_load_field:" " expected a name or string\n" )); FT_ERROR(( " " - " but found token of type %d instead\n", + " but found token of type %u instead\n", token.type )); error = FT_THROW( Invalid_File_Format ); goto Exit; @@ -1225,7 +1228,7 @@ if ( result < 0 || (FT_UInt)result < max_objects ) { FT_ERROR(( "ps_parser_load_field:" - " expected %d integer%s in the %s subarray\n", + " expected %u integer%s in the %s subarray\n", max_objects, max_objects > 1 ? "s" : "", i == 0 ? "first" : ( i == 1 ? "second" diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h index 345fc8a7335..277aa1247c5 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psobjs.h @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c index 5681c3bd0fd..66493b68123 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.c @@ -4,7 +4,7 @@ * * Type 1 character map support (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h index 445e6a2784f..114bfbb0410 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1cmap.h @@ -4,7 +4,7 @@ * * Type 1 character map support (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c index c74baa8038f..c3fb343d4c9 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.c @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (body). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1633,7 +1633,7 @@ default: FT_ERROR(( "t1_decoder_parse_charstrings:" - " unhandled opcode %d\n", op )); + " unhandled opcode %u\n", op )); goto Syntax_Error; } diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h index 16203b8f734..7b913f55dff 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h +++ b/src/java.desktop/share/native/libfreetype/src/psaux/t1decode.h @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (specification). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c index 967767b3485..ca30702321d 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.c @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (body). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -100,7 +100,7 @@ if ( idx >= table->max_hints ) { - FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx )); + FT_TRACE0(( "psh_hint_table_record: invalid hint index %u\n", idx )); return; } diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h index fb362f061b6..f4aa8540559 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshalgo.h @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (specification). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c index 435f45838ff..521a5ff6c5c 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.c @@ -5,7 +5,7 @@ * PostScript hinter global hinting management (body). * Inspired by the new auto-hinter module. * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h index c5a5c913168..555e99facb2 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshglob.h @@ -4,7 +4,7 @@ * * PostScript hinter global hinting management. * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c index 9965d5b16bf..c9f4a94fe98 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.c @@ -4,7 +4,7 @@ * * FreeType PostScript hinter module implementation (body). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h index 62ac0a60fdc..de9c398e9fb 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshmod.h @@ -4,7 +4,7 @@ * * PostScript hinter module interface (specification). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h index e9641340e53..7076664ddde 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshnterr.h @@ -4,7 +4,7 @@ * * PS Hinter error codes (specification only). * - * Copyright (C) 2003-2024 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c index 0b2b549fc29..13754313fbb 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.c @@ -4,7 +4,7 @@ * * FreeType PostScript hints recorder (body). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -467,7 +467,7 @@ table->num_masks--; } else - FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", + FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%u,%u)\n", index1, index2 )); Exit: @@ -817,7 +817,7 @@ /* limit "dimension" to 0..1 */ if ( dimension > 1 ) { - FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", + FT_TRACE0(( "ps_hints_stem: invalid dimension (%u) used\n", dimension )); dimension = ( dimension != 0 ); } @@ -870,7 +870,7 @@ /* limit "dimension" to 0..1 */ if ( dimension > 1 ) { - FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", + FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%u) used\n", dimension )); dimension = ( dimension != 0 ); } @@ -976,7 +976,7 @@ if ( bit_count != count1 + count2 ) { FT_TRACE0(( "ps_hints_t2mask:" - " called with invalid bitcount %d (instead of %d)\n", + " called with invalid bitcount %u (instead of %u)\n", bit_count, count1 + count2 )); /* simply ignore the operator */ @@ -1022,7 +1022,7 @@ if ( bit_count != count1 + count2 ) { FT_TRACE0(( "ps_hints_t2counter:" - " called with invalid bitcount %d (instead of %d)\n", + " called with invalid bitcount %u (instead of %u)\n", bit_count, count1 + count2 )); /* simply ignore the operator */ diff --git a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h index 7e375af7ba8..a79069f98d2 100644 --- a/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h +++ b/src/java.desktop/share/native/libfreetype/src/pshinter/pshrec.h @@ -4,7 +4,7 @@ * * Postscript (Type1/Type2) hints recorder (specification). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c index 35d054d1cfb..c5d71edad88 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c +++ b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.c @@ -4,7 +4,7 @@ * * psnames module implementation (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h index 770458316b1..482fd0a36d1 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h +++ b/src/java.desktop/share/native/libfreetype/src/psnames/psmodule.h @@ -4,7 +4,7 @@ * * High-level psnames module interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h b/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h index e123eb65e39..17987f9cd4f 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h +++ b/src/java.desktop/share/native/libfreetype/src/psnames/psnamerr.h @@ -4,7 +4,7 @@ * * PS names module error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h b/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h index 2a941b04609..65ce6c0b47f 100644 --- a/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h +++ b/src/java.desktop/share/native/libfreetype/src/psnames/pstables.h @@ -4,7 +4,7 @@ * * PostScript glyph names. * - * Copyright (C) 2005-2024 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h b/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h index 943f2aa0a50..9d97223e94e 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftmisc.h @@ -5,7 +5,7 @@ * Miscellaneous macros for stand-alone rasterizer (specification * only). * - * Copyright (C) 2005-2024 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c index e4b7b937d5a..807d444e7aa 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -251,7 +251,11 @@ /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */ /* for clipping computations. It simply uses the FT_MulDiv() function */ /* defined in `ftcalc.h'. */ -#define SMulDiv_No_Round FT_MulDiv_No_Round +#ifdef FT_INT64 +#define SMulDiv( a, b, c ) (Long)( (FT_Int64)(a) * (b) / (c) ) +#else +#define SMulDiv FT_MulDiv_No_Round +#endif /* The rasterizer is a very general purpose component; please leave */ /* the following redefinitions there (you never know your target */ @@ -653,7 +657,7 @@ ras.cProfile->height = 0; } - ras.cProfile->flags = ras.dropOutControl; + ras.cProfile->flags = ras.dropOutControl; switch ( aState ) { @@ -967,14 +971,14 @@ goto Fin; } - Ix = SMulDiv_No_Round( e - y1, Dx, Dy ); + Ix = SMulDiv( e - y1, Dx, Dy ); x1 += Ix; *top++ = x1; if ( --size ) { Ax = Dx * ( e - y1 ) - Dy * Ix; /* remainder */ - Ix = FMulDiv( ras.precision, Dx, Dy ); + Ix = SMulDiv( ras.precision, Dx, Dy ); Rx = Dx * ras.precision - Dy * Ix; /* remainder */ Dx = 1; @@ -1090,8 +1094,8 @@ PLong top; - y1 = arc[degree].y; - y2 = arc[0].y; + y1 = arc[degree].y; + y2 = arc[0].y; if ( y2 < miny || y1 > maxy ) return SUCCESS; diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h index ad9cb1b9fe0..64499bf955b 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c index fd9f174f2e1..3fa008704e5 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h index cf3e73c0a24..d838a942b04 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftrend1.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h b/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h index 326d42e0438..39d82a8051a 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h +++ b/src/java.desktop/share/native/libfreetype/src/raster/rasterrs.h @@ -4,7 +4,7 @@ * * monochrome renderer error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c index 76181568af9..9df75dc3acc 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.c @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h index 6e7a5c08e71..c59199e60df 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/pngshim.h @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2024 by + * Copyright (C) 2013-2025 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c index 81072207b49..ec78247aa56 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.c @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -895,7 +895,7 @@ FT_TRACE0(( "sfnt_get_var_ps_name:" " Shortening variation PS name prefix\n" )); FT_TRACE0(( " " - " to %d characters\n", len )); + " to %u characters\n", len )); } face->var_postscript_prefix = result; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h index 6f71489fdc1..be4e33166c1 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfdriver.h @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h index d3ca1d9aa8b..2da4ac776b0 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sferrors.h @@ -4,7 +4,7 @@ * * SFNT error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c index 6ee4e5e939b..6af35787e85 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c @@ -4,7 +4,7 @@ * * SFNT object management (base). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -579,6 +579,9 @@ if ( face_instance_index < 0 && face_index > 0 ) face_index--; + /* Note that `face_index` is also used to enumerate elements */ + /* of containers like a Mac Resource; this means we must */ + /* check whether we actually have a TTC. */ if ( face_index >= face->ttc_header.count ) { if ( face_instance_index >= 0 ) @@ -1127,9 +1130,9 @@ flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ - if ( TT_FACE_HAS_KERNING( face ) + if ( face->kern_avail_bits #ifdef TT_CONFIG_OPTION_GPOS_KERNING - || face->gpos_kerning_available + || face->num_gpos_lookups_kerning #endif ) flags |= FT_FACE_FLAG_KERNING; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h index 90847d95732..8c38b727950 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.h @@ -4,7 +4,7 @@ * * SFNT object management (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c index 14514bf9574..015c7b78b4d 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c @@ -4,7 +4,7 @@ * * WOFF format management (base). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h index a04735ffe28..df7ace5c209 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.h @@ -4,7 +4,7 @@ * * WOFFF format management (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c index 589b3e0c6b7..5acbbaa2a77 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.c @@ -4,7 +4,7 @@ * * WOFF2 format management (base). * - * Copyright (C) 2019-2024 by + * Copyright (C) 2019-2025 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -902,7 +902,7 @@ substreams[i].offset = pos + offset; substreams[i].size = substream_size; - FT_TRACE5(( " Substream %d: offset = %lu; size = %lu;\n", + FT_TRACE5(( " Substream %u: offset = %lu; size = %lu;\n", i, substreams[i].offset, substreams[i].size )); offset += substream_size; } @@ -1592,7 +1592,7 @@ WOFF2_TableRec table = *( indices[nn] ); - FT_TRACE3(( "Seeking to %ld with table size %ld.\n", + FT_TRACE3(( "Seeking to %lu with table size %lu.\n", table.src_offset, table.src_length )); FT_TRACE3(( "Table tag: %c%c%c%c.\n", (FT_Char)( table.Tag >> 24 ), @@ -1943,7 +1943,7 @@ src_offset += table->TransformLength; table->dst_offset = 0; - FT_TRACE2(( " %c%c%c%c %08d %08d %08ld %08ld %08ld\n", + FT_TRACE2(( " %c%c%c%c %08d %08d %08lu %08lu %08lu\n", (FT_Char)( table->Tag >> 24 ), (FT_Char)( table->Tag >> 16 ), (FT_Char)( table->Tag >> 8 ), diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h index f41140648dc..588761d0c8e 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff2.h @@ -4,7 +4,7 @@ * * WOFFF2 format management (specification). * - * Copyright (C) 2019-2024 by + * Copyright (C) 2019-2025 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c index 28f4d1173c0..91b02344224 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (body). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -179,7 +179,7 @@ cmap_info->format = 0; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -596,7 +596,7 @@ cmap_info->format = 2; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -1539,7 +1539,7 @@ cmap_info->format = 4; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -1712,7 +1712,7 @@ cmap_info->format = 6; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -2009,7 +2009,7 @@ cmap_info->format = 8; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -2184,7 +2184,7 @@ cmap_info->format = 10; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -2528,7 +2528,7 @@ cmap_info->format = 12; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -2844,7 +2844,7 @@ cmap_info->format = 13; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -3792,7 +3792,7 @@ return FT_THROW( Invalid_Table ); /* Version 1.8.3 of the OpenType specification contains the following */ - /* (https://docs.microsoft.com/en-us/typography/opentype/spec/cmap): */ + /* (https://learn.microsoft.com/typography/opentype/spec/cmap): */ /* */ /* The 'cmap' table version number remains at 0x0000 for fonts that */ /* make use of the newer subtable formats. */ @@ -3803,7 +3803,7 @@ p += 2; num_cmaps = TT_NEXT_USHORT( p ); - FT_TRACE4(( "tt_face_build_cmaps: %d cmaps\n", num_cmaps )); + FT_TRACE4(( "tt_face_build_cmaps: %u cmaps\n", num_cmaps )); limit = table + face->cmap_size; for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h index e2c5e72bf02..645e9e37e0c 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2024 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h index 370898363f3..65807bb7378 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h @@ -4,7 +4,7 @@ * * TT CMAP classes definitions (specification only). * - * Copyright (C) 2009-2024 by + * Copyright (C) 2009-2025 by * Oran Agra and Mickey Gabel. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c index b37658dde9e..ad9ad6f2710 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (body). * - * Copyright (C) 2018-2024 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. * * Originally written by Shao Yu Zhang . @@ -51,7 +51,7 @@ #define COLOR_STOP_SIZE 6U #define VAR_IDX_BASE_SIZE 4U #define LAYER_SIZE 4U -/* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#colr-header */ +/* https://learn.microsoft.com/typography/opentype/spec/colr#colr-header */ /* 3 * uint16 + 2 * Offset32 */ #define COLRV0_HEADER_SIZE 14U /* COLRV0_HEADER_SIZE + 5 * Offset32 */ diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h index 30031464c73..3913acc74d5 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.h @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (specification). * - * Copyright (C) 2018-2024 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c index 997eb869ffc..6d1208f6af2 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.c @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (body). * - * Copyright (C) 2018-2024 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h index bb301ae88b6..a0b4c9d927f 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcpal.h @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (specification). * - * Copyright (C) 2018-2024 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c index f0411366af4..76618b0d3bb 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.c @@ -2,10 +2,9 @@ * * ttkern.c * - * Load the basic TrueType kerning table. This doesn't handle - * kerning data within the GPOS table at the moment. + * Routines to parse and access the 'kern' table for kerning (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h index a54e51df12d..e0075dce61d 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttkern.h @@ -2,10 +2,10 @@ * * ttkern.h * - * Load the basic TrueType kerning table. This doesn't handle - * kerning data within the GPOS table at the moment. + * Routines to parse and access the 'kern' table for kerning + * (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -40,8 +40,6 @@ FT_BEGIN_HEADER FT_UInt left_glyph, FT_UInt right_glyph ); -#define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) - FT_END_HEADER diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c index c3a5fae2cb9..0c257ce4d31 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -535,7 +535,8 @@ * The tag of table to load. Use the value 0 if you want * to access the whole font file, else set this parameter * to a valid TrueType table tag that you can forge with - * the MAKE_TT_TAG macro. + * the MAKE_TT_TAG macro. Use value 1 to access the table + * directory. * * offset :: * The starting offset in the table (or the file if @@ -577,7 +578,29 @@ FT_ULong size; - if ( tag != 0 ) + if ( tag == 0 ) + { + /* The whole font file. */ + size = face->root.stream->size; + } + else if ( tag == 1 ) + { + /* The currently selected font's table directory. */ + /* */ + /* Note that `face_index` is also used to enumerate elements */ + /* of containers like a Mac Resource; this means we must */ + /* check whether we actually have a TTC (with multiple table */ + /* directories). */ + FT_Long idx = face->root.face_index & 0xFFFF; + + + if ( idx >= face->ttc_header.count ) + idx = 0; + + offset += face->ttc_header.offsets[idx]; + size = 4 + 8 + 16 * face->num_tables; + } + else { /* look for tag in font directory */ table = tt_face_lookup_table( face, tag ); @@ -590,9 +613,6 @@ offset += table->Offset; size = table->Length; } - else - /* tag == 0 -- the user wants to access the font file directly */ - size = face->root.stream->size; if ( length && *length == 0 ) { diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h index 2b1d62d9bd9..e3666c901b1 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.h @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c index 27884118563..541d8447470 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (body). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -306,7 +306,7 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( var && face->blend ) + if ( var && FT_IS_VARIATION( &face->root ) ) { FT_Face f = FT_FACE( face ); FT_Int a = (FT_Int)*aadvance; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h index 34b3c0e18f2..1ee84507f15 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.h @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (specification). * - * Copyright (C) 2006-2024 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c index 5698a62c8d1..4246b6c8eff 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h index 150db6c3981..a11b6696854 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.h @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c index cb3a8abf182..9f9013bf39b 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (body). * - * Copyright (C) 2005-2024 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Copyright 2013 by Google, Inc. @@ -342,7 +342,7 @@ FT_TRACE2(( "tt_face_load_strike_metrics:" " sanitizing invalid ascender and descender\n" )); FT_TRACE2(( " " - " values for strike %ld (%dppem, %dppem)\n", + " values for strike %lu (%dppem, %dppem)\n", strike_index, metrics->x_ppem, metrics->y_ppem )); @@ -993,7 +993,7 @@ goto Fail; } - FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %d component%s\n", + FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %u component%s\n", num_components, num_components == 1 ? "" : "s" )); @@ -1419,7 +1419,7 @@ image_start = image_offset + image_start; FT_TRACE3(( "tt_sbit_decoder_load_image:" - " found sbit (format %d) for glyph index %d\n", + " found sbit (format %u) for glyph index %u\n", image_format, glyph_index )); return tt_sbit_decoder_load_bitmap( decoder, @@ -1438,13 +1438,13 @@ if ( recurse_count ) { FT_TRACE4(( "tt_sbit_decoder_load_image:" - " missing subglyph sbit with glyph index %d\n", + " missing subglyph sbit with glyph index %u\n", glyph_index )); return FT_THROW( Invalid_Composite ); } FT_TRACE4(( "tt_sbit_decoder_load_image:" - " no sbit found for glyph index %d\n", glyph_index )); + " no sbit found for glyph index %u\n", glyph_index )); return FT_THROW( Missing_Bitmap ); } @@ -1462,12 +1462,13 @@ FT_Int originOffsetX, originOffsetY; FT_Tag graphicType; FT_Int recurse_depth = 0; + FT_Bool flipped = FALSE; FT_Error error; FT_Byte* p; - FT_UNUSED( map ); #ifndef FT_CONFIG_OPTION_USE_PNG + FT_UNUSED( map ); FT_UNUSED( metrics_only ); #endif @@ -1517,12 +1518,16 @@ switch ( graphicType ) { + case FT_MAKE_TAG( 'f', 'l', 'i', 'p' ): + flipped = !flipped; + FALL_THROUGH; + case FT_MAKE_TAG( 'd', 'u', 'p', 'e' ): - if ( recurse_depth < 4 ) + if ( recurse_depth++ < 4 ) { glyph_index = FT_GET_USHORT(); FT_FRAME_EXIT(); - recurse_depth++; + goto retry; } error = FT_THROW( Invalid_File_Format ); @@ -1540,6 +1545,38 @@ glyph_end - glyph_start - 8, TRUE, metrics_only ); + if ( flipped && !metrics_only && !error ) + { + FT_UInt32* curr_pos = (FT_UInt32*)map->buffer; + + /* `Load_SBit_Png` always returns a pixmap with 32 bits per pixel */ + /* and no extra pitch bytes. */ + FT_UInt width = map->width; + FT_UInt y; + + + for ( y = 0; y < map->rows; y++ ) + { + FT_UInt32* left = curr_pos; + FT_UInt32* right = curr_pos + width - 1; + + + while ( left < right ) + { + FT_UInt32 value; + + + value = *right; + *right = *left; + *left = value; + + left++; + right--; + } + + curr_pos += width; + } + } #else error = FT_THROW( Unimplemented_Feature ); #endif diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h index 96f80a58424..7427149d68f 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c index 532ccfa1737..0f9e3889aab 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.c @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (base). * - * Copyright (C) 2019-2024 by + * Copyright (C) 2019-2025 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h index d03b4b41bc9..e223022962e 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/woff2tags.h @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (specification). * - * Copyright (C) 2019-2024 by + * Copyright (C) 2019-2025 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c index b7c0632a6fa..365fbad42ad 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c @@ -4,7 +4,7 @@ * * A new `perfect' anti-aliasing renderer (body). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -157,10 +157,6 @@ #define ft_memset memset -#define ft_setjmp setjmp -#define ft_longjmp longjmp -#define ft_jmp_buf jmp_buf - typedef ptrdiff_t FT_PtrDist; @@ -170,8 +166,8 @@ typedef ptrdiff_t FT_PtrDist; #define Smooth_Err_Invalid_Argument -3 #define Smooth_Err_Raster_Overflow -4 -#define FT_BEGIN_HEADER -#define FT_END_HEADER +#define FT_BEGIN_HEADER /* nothing */ +#define FT_END_HEADER /* nothing */ #include "ftimage.h" #include "ftgrays.h" @@ -495,6 +491,7 @@ typedef ptrdiff_t FT_PtrDist; TCoord min_ey, max_ey; TCoord count_ey; /* same as (max_ey - min_ey) */ + int error; /* pool overflow exception */ PCell cell; /* current cell */ PCell cell_free; /* call allocation next free slot */ PCell cell_null; /* last cell, used as dumpster and limit */ @@ -510,8 +507,6 @@ typedef ptrdiff_t FT_PtrDist; FT_Raster_Span_Func render_span; void* render_span_data; - ft_jmp_buf jump_buffer; - } gray_TWorker, *gray_PWorker; #if defined( _MSC_VER ) @@ -613,9 +608,14 @@ typedef ptrdiff_t FT_PtrDist; } /* insert new cell */ - cell = ras.cell_free++; - if ( cell >= ras.cell_null ) - ft_longjmp( ras.jump_buffer, 1 ); + cell = ras.cell_free; + if ( cell == ras.cell_null ) + { + ras.error = FT_THROW( Raster_Overflow ); + goto Found; + } + + ras.cell_free = cell + 1; cell->x = ex; cell->area = 0; @@ -1353,7 +1353,8 @@ typedef ptrdiff_t FT_PtrDist; ras.x = x; ras.y = y; - return 0; + + return ras.error; } @@ -1365,7 +1366,8 @@ typedef ptrdiff_t FT_PtrDist; gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); - return 0; + + return ras.error; } @@ -1378,7 +1380,8 @@ typedef ptrdiff_t FT_PtrDist; gray_render_conic( RAS_VAR_ control, to ); - return 0; + + return ras.error; } @@ -1392,7 +1395,8 @@ typedef ptrdiff_t FT_PtrDist; gray_render_cubic( RAS_VAR_ control1, control2, to ); - return 0; + + return ras.error; } @@ -1700,30 +1704,22 @@ typedef ptrdiff_t FT_PtrDist; gray_convert_glyph_inner( RAS_ARG_ int continued ) { - volatile int error; + int error; - if ( ft_setjmp( ras.jump_buffer ) == 0 ) - { - if ( continued ) - FT_Trace_Disable(); - error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); - if ( continued ) - FT_Trace_Enable(); + if ( continued ) + FT_Trace_Disable(); + error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); + if ( continued ) + FT_Trace_Enable(); - FT_TRACE7(( "band [%d..%d]: %td cell%s remaining\n", - ras.min_ey, - ras.max_ey, - ras.cell_null - ras.cell_free, - ras.cell_null - ras.cell_free == 1 ? "" : "s" )); - } - else - { - error = FT_THROW( Raster_Overflow ); - - FT_TRACE7(( "band [%d..%d]: to be bisected\n", - ras.min_ey, ras.max_ey )); - } + FT_TRACE7(( error == Smooth_Err_Raster_Overflow + ? "band [%d..%d]: to be bisected\n" + : "band [%d..%d]: %td cell%s remaining\n", + ras.min_ey, + ras.max_ey, + ras.cell_null - ras.cell_free, + ras.cell_null - ras.cell_free == 1 ? "" : "s" )); return error; } @@ -1873,6 +1869,7 @@ typedef ptrdiff_t FT_PtrDist; TCoord* band; int continued = 0; + int error = Smooth_Err_Ok; /* Initialize the null cell at the end of the poll. */ @@ -1907,7 +1904,6 @@ typedef ptrdiff_t FT_PtrDist; do { TCoord i; - int error; ras.min_ex = band[1]; @@ -1922,6 +1918,7 @@ typedef ptrdiff_t FT_PtrDist; ras.cell_free = buffer + n; ras.cell = ras.cell_null; + ras.error = Smooth_Err_Ok; error = gray_convert_glyph_inner( RAS_VAR_ continued ); continued = 1; @@ -1936,7 +1933,7 @@ typedef ptrdiff_t FT_PtrDist; continue; } else if ( error != Smooth_Err_Raster_Overflow ) - return error; + goto Exit; /* render pool overflow; we will reduce the render band by half */ i = ( band[0] - band[1] ) >> 1; @@ -1945,7 +1942,8 @@ typedef ptrdiff_t FT_PtrDist; if ( i == 0 ) { FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); - return FT_THROW( Raster_Overflow ); + error = FT_THROW( Raster_Overflow ); + goto Exit; } band++; @@ -1954,7 +1952,11 @@ typedef ptrdiff_t FT_PtrDist; } while ( band >= bands ); } - return Smooth_Err_Ok; + Exit: + ras.cell = ras.cell_free = ras.cell_null = NULL; + ras.ycells = NULL; + + return error; } diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h index 940fbe8c79b..e463e5b3eb8 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.h @@ -4,7 +4,7 @@ * * FreeType smooth renderer declaration * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,11 +19,6 @@ #ifndef FTGRAYS_H_ #define FTGRAYS_H_ -#ifdef __cplusplus - extern "C" { -#endif - - #ifdef STANDALONE_ #include "ftimage.h" #else @@ -31,6 +26,7 @@ #include #endif +FT_BEGIN_HEADER /************************************************************************** * @@ -46,10 +42,7 @@ FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster; - -#ifdef __cplusplus - } -#endif +FT_END_HEADER #endif /* FTGRAYS_H_ */ diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h index 6d41fb8e0fd..8d5068549fa 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmerrs.h @@ -4,7 +4,7 @@ * * smooth renderer error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c index f0acc1ea4a6..21a6eca00ba 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (body). * - * Copyright (C) 2000-2024 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h index d7b61a9e60e..f76708ae701 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.h @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c index 4ab68eb9a12..6369d83d6d5 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c @@ -4,7 +4,7 @@ * * TrueType font driver implementation (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -220,12 +220,12 @@ { /* Use 'kern' table if available since that can be faster; otherwise */ /* use GPOS kerning pairs if available. */ - if ( ttface->kern_avail_bits != 0 ) + if ( ttface->kern_avail_bits ) kerning->x = sfnt->get_kerning( ttface, left_glyph, right_glyph ); #ifdef TT_CONFIG_OPTION_GPOS_KERNING - else if ( ttface->gpos_kerning_available ) + else if ( ttface->num_gpos_lookups_kerning ) kerning->x = sfnt->get_gpos_kerning( ttface, left_glyph, right_glyph ); diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h index 3e1cf234fcf..943eaae3482 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.h @@ -4,7 +4,7 @@ * * High-level TrueType driver interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h b/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h index 7ad937bd04d..631dbf5a80f 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/tterrors.h @@ -4,7 +4,7 @@ * * TrueType error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c index b656ccf04e3..e810ebfd550 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -660,7 +660,7 @@ } while ( subglyph->flags & MORE_COMPONENTS ); gloader->current.num_subglyphs = num_subglyphs; - FT_TRACE5(( " %d component%s\n", + FT_TRACE5(( " %u component%s\n", num_subglyphs, num_subglyphs > 1 ? "s" : "" )); @@ -674,7 +674,7 @@ for ( i = 0; i < num_subglyphs; i++ ) { if ( num_subglyphs > 1 ) - FT_TRACE7(( " subglyph %d:\n", i )); + FT_TRACE7(( " subglyph %u:\n", i )); FT_TRACE7(( " glyph index: %d\n", subglyph->index )); @@ -777,15 +777,11 @@ TT_Hint_Glyph( TT_Loader loader, FT_Bool is_composite ) { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - TT_Face face = loader->face; - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); -#endif - TT_GlyphZone zone = &loader->zone; #ifdef TT_USE_BYTECODE_INTERPRETER TT_ExecContext exec = loader->exec; + TT_Size size = loader->size; FT_Long n_ins = exec->glyphSize; #else FT_UNUSED( is_composite ); @@ -797,9 +793,6 @@ if ( n_ins > 0 ) FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); - /* Reset graphics state. */ - exec->GS = loader->size->GS; - /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */ /* completely refer to the (already) hinted subglyphs. */ if ( is_composite ) @@ -811,8 +804,8 @@ } else { - exec->metrics.x_scale = loader->size->metrics->x_scale; - exec->metrics.y_scale = loader->size->metrics->y_scale; + exec->metrics.x_scale = size->metrics->x_scale; + exec->metrics.y_scale = size->metrics->y_scale; } #endif @@ -838,7 +831,7 @@ exec->is_composite = is_composite; exec->pts = *zone; - error = TT_Run_Context( exec ); + error = TT_Run_Context( exec, size ); if ( error && exec->pedantic_hinting ) return error; @@ -854,8 +847,7 @@ /* to change bearings or advance widths. */ #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && - exec->backward_compatibility ) + if ( exec->backward_compatibility ) return FT_Err_Ok; #endif @@ -1152,30 +1144,15 @@ x = FT_MulFix( x, x_scale ); y = FT_MulFix( y, y_scale ); - if ( subglyph->flags & ROUND_XY_TO_GRID ) + if ( subglyph->flags & ROUND_XY_TO_GRID && + IS_HINTED( loader->load_flags ) ) { - TT_Face face = loader->face; - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !loader->exec->backward_compatibility ) +#endif + x = FT_PIX_ROUND( x ); - - if ( IS_HINTED( loader->load_flags ) ) - { - /* - * We round the horizontal offset only if there is hinting along - * the x axis; this corresponds to integer advance width values. - * - * Theoretically, a glyph's bytecode can toggle ClearType's - * `backward compatibility' mode, which would allow modification - * of the advance width. In reality, however, applications - * neither allow nor expect modified advance widths if subpixel - * rendering is active. - * - */ - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_35 ) - x = FT_PIX_ROUND( x ); - - y = FT_PIX_ROUND( y ); - } + y = FT_PIX_ROUND( y ); } } } @@ -1204,8 +1181,6 @@ { FT_Error error; FT_Outline* outline = &loader->gloader->base.outline; - FT_Stream stream = loader->stream; - FT_UShort n_ins; FT_UInt i; @@ -1224,8 +1199,10 @@ #ifdef TT_USE_BYTECODE_INTERPRETER { - TT_ExecContext exec = loader->exec; + TT_ExecContext exec = loader->exec; FT_Memory memory = exec->memory; + FT_Stream stream = loader->stream; + FT_UShort n_ins; if ( exec->glyphSize ) @@ -1378,8 +1355,9 @@ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && loader->exec && - loader->exec->subpixel_hinting_lean && - loader->exec->grayscale_cleartype ) + loader->exec->mode != FT_RENDER_MODE_MONO && + loader->exec->mode != FT_RENDER_MODE_LCD && + loader->exec->mode != FT_RENDER_MODE_LCD_V ) { loader->pp3.x = loader->advance / 2; loader->pp4.x = loader->advance / 2; @@ -1444,13 +1422,13 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( recurse_count ) - FT_TRACE5(( " nesting level: %d\n", recurse_count )); + FT_TRACE5(( " nesting level: %u\n", recurse_count )); #endif /* some fonts have an incorrect value of `maxComponentDepth' */ if ( recurse_count > face->max_profile.maxComponentDepth ) { - FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %d\n", + FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %u\n", recurse_count )); face->max_profile.maxComponentDepth = (FT_UShort)recurse_count; } @@ -1566,18 +1544,18 @@ if ( header_only ) goto Exit; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incremental( loader, glyph_index ); +#endif + tt_loader_set_pp( loader ); + + /* shortcut for empty glyphs */ if ( loader->byte_len == 0 || loader->n_contours == 0 ) { -#ifdef FT_CONFIG_OPTION_INCREMENTAL - tt_get_metrics_incremental( loader, glyph_index ); -#endif - tt_loader_set_pp( loader ); - #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || - FT_IS_VARIATION( FT_FACE( face ) ) ) + if ( !IS_DEFAULT_INSTANCE( FT_FACE( face ) ) ) { /* a small outline structure with four elements for */ /* communication with `TT_Vary_Apply_Glyph_Deltas' */ @@ -1627,11 +1605,6 @@ goto Exit; } -#ifdef FT_CONFIG_OPTION_INCREMENTAL - tt_get_metrics_incremental( loader, glyph_index ); -#endif - tt_loader_set_pp( loader ); - /***********************************************************************/ /***********************************************************************/ @@ -1735,8 +1708,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || - FT_IS_VARIATION( FT_FACE( face ) ) ) + if ( !IS_DEFAULT_INSTANCE( FT_FACE( face ) ) ) { FT_UShort i, limit; FT_SubGlyph subglyph; @@ -1953,6 +1925,9 @@ #ifdef FT_CONFIG_OPTION_INCREMENTAL + /* restore the original stream */ + loader->stream = face->root.stream; + if ( glyph_data_loaded ) face->root.internal->incremental_interface->funcs->free_glyph_data( face->root.internal->incremental_interface->object, @@ -2112,7 +2087,6 @@ { TT_Face face = (TT_Face)glyph->face; SFNT_Service sfnt = (SFNT_Service)face->sfnt; - FT_Stream stream = face->root.stream; FT_Error error; TT_SBit_MetricsRec sbit_metrics; @@ -2121,14 +2095,11 @@ size->strike_index, glyph_index, (FT_UInt)load_flags, - stream, + face->root.stream, &glyph->bitmap, &sbit_metrics ); if ( !error ) { - glyph->outline.n_points = 0; - glyph->outline.n_contours = 0; - glyph->metrics.width = (FT_Pos)sbit_metrics.width * 64; glyph->metrics.height = (FT_Pos)sbit_metrics.height * 64; @@ -2153,6 +2124,50 @@ glyph->bitmap_top = sbit_metrics.horiBearingY; } } + /* a missing glyph in a bitmap-only font is assumed whitespace */ + /* that needs to be constructed using metrics data from `hmtx' */ + /* and, optionally, `vmtx' tables */ + else if ( FT_ERR_EQ( error, Missing_Bitmap ) && + !FT_IS_SCALABLE( glyph->face ) && + face->horz_metrics_size ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short left_bearing = 0; + FT_Short top_bearing = 0; + + FT_UShort advance_width = 0; + FT_UShort advance_height = 0; + + + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + 0, + &top_bearing, + &advance_height ); + + glyph->metrics.width = 0; + glyph->metrics.height = 0; + + glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale ); + glyph->metrics.horiBearingY = 0; + glyph->metrics.horiAdvance = FT_MulFix( advance_width, x_scale ); + + glyph->metrics.vertBearingX = 0; + glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advance_height, y_scale ); + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + glyph->bitmap_left = 0; + glyph->bitmap_top = 0; + + error = FT_Err_Ok; + } return error; } @@ -2168,15 +2183,6 @@ FT_Bool glyf_table_only ) { TT_Face face = (TT_Face)glyph->face; - FT_Stream stream = face->root.stream; - -#ifdef TT_USE_BYTECODE_INTERPRETER - FT_Error error; - FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( glyph->face ); -#endif -#endif FT_ZERO( loader ); @@ -2186,122 +2192,78 @@ /* load execution context */ if ( IS_HINTED( load_flags ) && !glyf_table_only ) { + FT_Error error; TT_ExecContext exec; - FT_Bool grayscale = TRUE; + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + FT_Bool grayscale = FT_BOOL( mode != FT_RENDER_MODE_MONO ); + FT_Bool reexecute = FALSE; #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - FT_Bool subpixel_hinting_lean; - FT_Bool grayscale_cleartype; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( glyph->face ); #endif - FT_Bool reexecute = FALSE; - - if ( size->bytecode_ready < 0 || size->cvt_ready < 0 ) + if ( size->bytecode_ready > 0 ) + return size->bytecode_ready; + if ( size->bytecode_ready < 0 ) { - error = tt_size_ready_bytecode( size, pedantic ); + FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); + + + error = tt_size_init_bytecode( size, pedantic ); if ( error ) return error; } - else if ( size->bytecode_ready ) - return size->bytecode_ready; - else if ( size->cvt_ready ) - return size->cvt_ready; - /* query new execution context */ exec = size->context; - if ( !exec ) - return FT_THROW( Could_Not_Find_Context ); - - grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - FT_RENDER_MODE_MONO ); #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) { - subpixel_hinting_lean = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - FT_RENDER_MODE_MONO ); - grayscale_cleartype = - FT_BOOL( subpixel_hinting_lean && - !( ( load_flags & - FT_LOAD_TARGET_LCD ) || - ( load_flags & - FT_LOAD_TARGET_LCD_V ) ) ); - exec->vertical_lcd_lean = - FT_BOOL( subpixel_hinting_lean && - ( load_flags & - FT_LOAD_TARGET_LCD_V ) ); - grayscale = FT_BOOL( grayscale && !subpixel_hinting_lean ); - } - else - { - subpixel_hinting_lean = FALSE; - grayscale_cleartype = FALSE; - exec->vertical_lcd_lean = FALSE; + grayscale = FALSE; + + /* any mode change requires a re-execution of the CVT program */ + if ( mode != exec->mode ) + { + FT_TRACE4(( "tt_loader_init: render mode change," + " re-executing `prep' table\n" )); + + exec->mode = mode; + reexecute = TRUE; + } } #endif + /* a change from mono to grayscale rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale ) + { + FT_TRACE4(( "tt_loader_init: grayscale hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale = grayscale; + reexecute = TRUE; + } + + if ( size->cvt_ready > 0 ) + return size->cvt_ready; + if ( size->cvt_ready < 0 || reexecute ) + { + error = tt_size_run_prep( size ); + if ( error ) + return error; + } + error = TT_Load_Context( exec, face, size ); if ( error ) return error; - { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) - { - /* a change from mono to subpixel rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( subpixel_hinting_lean != exec->subpixel_hinting_lean ) - { - FT_TRACE4(( "tt_loader_init: subpixel hinting change," - " re-executing `prep' table\n" )); - - exec->subpixel_hinting_lean = subpixel_hinting_lean; - reexecute = TRUE; - } - - /* a change from colored to grayscale subpixel rendering (and */ - /* vice versa) requires a re-execution of the CVT program */ - if ( grayscale_cleartype != exec->grayscale_cleartype ) - { - FT_TRACE4(( "tt_loader_init: grayscale subpixel hinting change," - " re-executing `prep' table\n" )); - - exec->grayscale_cleartype = grayscale_cleartype; - reexecute = TRUE; - } - } -#endif - - /* a change from mono to grayscale rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( grayscale != exec->grayscale ) - { - FT_TRACE4(( "tt_loader_init: grayscale hinting change," - " re-executing `prep' table\n" )); - - exec->grayscale = grayscale; - reexecute = TRUE; - } - } - - if ( reexecute ) - { - error = tt_size_run_prep( size, pedantic ); - if ( error ) - return error; - error = TT_Load_Context( exec, face, size ); - if ( error ) - return error; - } - /* check whether the cvt program has disabled hinting */ - if ( exec->GS.instruct_control & 1 ) + if ( size->GS.instruct_control & 1 ) load_flags |= FT_LOAD_NO_HINTING; - /* load default graphics state -- if needed */ - if ( exec->GS.instruct_control & 2 ) - exec->GS = tt_default_graphics_state; + /* check whether GS modifications should be reverted */ + if ( size->GS.instruct_control & 2 ) + size->GS = tt_default_graphics_state; #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* @@ -2318,28 +2280,25 @@ * */ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && - subpixel_hinting_lean && + mode != FT_RENDER_MODE_MONO && !FT_IS_TRICKY( glyph->face ) ) - exec->backward_compatibility = !( exec->GS.instruct_control & 4 ); + exec->backward_compatibility = ( size->GS.instruct_control & 4 ) ^ 4; else - exec->backward_compatibility = FALSE; + exec->backward_compatibility = 0; #endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ - exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); loader->exec = exec; - loader->instructions = exec->glyphIns; /* Use the hdmx table if any unless FT_LOAD_COMPUTE_METRICS */ /* is set or backward compatibility mode of the v38 or v40 */ /* interpreters is active. See `ttinterp.h' for details on */ /* backward compatibility mode. */ - if ( IS_HINTED( loader->load_flags ) && - !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) && + if ( IS_HINTED( load_flags ) && + !( load_flags & FT_LOAD_COMPUTE_METRICS ) && #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && - exec->backward_compatibility ) && + !exec->backward_compatibility && #endif - !face->postscript.isFixedPitch ) + !face->postscript.isFixedPitch ) { loader->widthp = size->widthp; } @@ -2364,7 +2323,7 @@ loader->face = face; loader->size = size; loader->glyph = (FT_GlyphSlot)glyph; - loader->stream = stream; + loader->stream = face->root.stream; loader->composites.head = NULL; loader->composites.tail = NULL; @@ -2426,84 +2385,26 @@ TT_LoaderRec loader; - FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index )); + FT_TRACE1(( "TT_Load_Glyph: glyph index %u\n", glyph_index )); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* try to load embedded bitmap (if any) */ - if ( size->strike_index != 0xFFFFFFFFUL && - ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && - IS_DEFAULT_INSTANCE( glyph->face ) ) + if ( size->strike_index != 0xFFFFFFFFUL && + !( load_flags & FT_LOAD_NO_BITMAP && + FT_IS_SCALABLE( glyph->face ) ) && + IS_DEFAULT_INSTANCE( glyph->face ) ) { - FT_Fixed x_scale = size->root.metrics.x_scale; - FT_Fixed y_scale = size->root.metrics.y_scale; - - error = load_sbit_image( size, glyph, glyph_index, load_flags ); - if ( FT_ERR_EQ( error, Missing_Bitmap ) ) - { - /* the bitmap strike is incomplete and misses the requested glyph; */ - /* if we have a bitmap-only font, return an empty glyph */ - if ( !FT_IS_SCALABLE( glyph->face ) ) - { - FT_Short left_bearing = 0; - FT_Short top_bearing = 0; - - FT_UShort advance_width = 0; - FT_UShort advance_height = 0; - - - /* to return an empty glyph, however, we need metrics data */ - /* from the `hmtx' (or `vmtx') table; the assumption is that */ - /* empty glyphs are missing intentionally, representing */ - /* whitespace - not having at least horizontal metrics is */ - /* thus considered an error */ - if ( !face->horz_metrics_size ) - return error; - - /* we now construct an empty bitmap glyph */ - TT_Get_HMetrics( face, glyph_index, - &left_bearing, - &advance_width ); - TT_Get_VMetrics( face, glyph_index, - 0, - &top_bearing, - &advance_height ); - - glyph->outline.n_points = 0; - glyph->outline.n_contours = 0; - - glyph->metrics.width = 0; - glyph->metrics.height = 0; - - glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale ); - glyph->metrics.horiBearingY = 0; - glyph->metrics.horiAdvance = FT_MulFix( advance_width, x_scale ); - - glyph->metrics.vertBearingX = 0; - glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale ); - glyph->metrics.vertAdvance = FT_MulFix( advance_height, y_scale ); - - glyph->format = FT_GLYPH_FORMAT_BITMAP; - glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO; - - glyph->bitmap_left = 0; - glyph->bitmap_top = 0; - - return FT_Err_Ok; - } - } - else if ( error ) - { - /* return error if font is not scalable */ - if ( !FT_IS_SCALABLE( glyph->face ) ) - return error; - } - else + if ( !error ) { if ( FT_IS_SCALABLE( glyph->face ) || FT_HAS_SBIX( glyph->face ) ) { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + /* for the bbox we need the header only */ (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); @@ -2550,8 +2451,10 @@ y_scale ); } - return FT_Err_Ok; + goto Exit; } + else if ( !FT_IS_SCALABLE( glyph->face ) ) + goto Exit; } if ( load_flags & FT_LOAD_SBITS_ONLY ) @@ -2563,7 +2466,7 @@ #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */ - if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid ) + if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.ppem ) { error = FT_THROW( Invalid_Size_Handle ); goto Exit; @@ -2614,7 +2517,7 @@ glyph->metrics.horiAdvance = FT_MulFix( advanceX, x_scale ); glyph->metrics.vertAdvance = FT_MulFix( advanceY, y_scale ); - return error; + goto Exit; } FT_TRACE3(( "Failed to load SVG glyph\n" )); @@ -2642,10 +2545,6 @@ goto Done; } - glyph->format = FT_GLYPH_FORMAT_OUTLINE; - glyph->num_subglyphs = 0; - glyph->outline.flags = 0; - /* main loading loop */ error = load_truetype_glyph( &loader, glyph_index, 0, FALSE ); if ( !error ) @@ -2657,9 +2556,18 @@ } else { + glyph->format = FT_GLYPH_FORMAT_OUTLINE; + glyph->outline = loader.gloader->base.outline; glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; + /* Set the `high precision' bit flag. This is _critical_ to */ + /* get correct output for monochrome TrueType glyphs at all */ + /* sizes using the bytecode interpreter. */ + if ( !( load_flags & FT_LOAD_NO_SCALE ) && + size->metrics->y_ppem < 24 ) + glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + /* Translate array so that (0,0) is the glyph's origin. Note */ /* that this behaviour is independent on the value of bit 1 of */ /* the `flags' field in the `head' table -- at least major */ @@ -2708,14 +2616,6 @@ error = compute_glyph_metrics( &loader, glyph_index ); } - /* Set the `high precision' bit flag. */ - /* This is _critical_ to get correct output for monochrome */ - /* TrueType glyphs at all sizes using the bytecode interpreter. */ - /* */ - if ( !( load_flags & FT_LOAD_NO_SCALE ) && - size->metrics->y_ppem < 24 ) - glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - FT_TRACE1(( " subglyphs = %u, contours = %hu, points = %hu," " flags = 0x%.3x\n", loader.gloader->base.num_subglyphs, @@ -2727,11 +2627,8 @@ tt_loader_done( &loader ); Exit: -#ifdef FT_DEBUG_LEVEL_TRACE - if ( error ) - FT_TRACE1(( " failed (error code 0x%x)\n", - error )); -#endif + FT_TRACE1(( error ? " failed (error code 0x%x)\n" : "", + error )); return error; } diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h index 22ea967f301..39d6ae3664c 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.h @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c index 4f0083c96b7..0732fcbae36 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. * * This file is part of the FreeType project, and may only be used, @@ -489,8 +489,9 @@ FT_UShort axis_count; FT_UInt region_count; - FT_UInt i, j; - FT_Bool long_words; + FT_UInt i, j; + FT_Byte* bytes; + FT_Bool long_words; GX_Blend blend = ttface->blend; FT_ULong* dataOffsetArray = NULL; @@ -526,11 +527,15 @@ if ( FT_QNEW_ARRAY( dataOffsetArray, data_count ) ) goto Exit; + if ( FT_FRAME_ENTER( data_count * 4 ) ) + goto Exit; + + bytes = stream->cursor; + for ( i = 0; i < data_count; i++ ) - { - if ( FT_READ_ULONG( dataOffsetArray[i] ) ) - goto Exit; - } + dataOffsetArray[i] = FT_NEXT_ULONG( bytes ); + + FT_FRAME_EXIT(); /* parse array of region records (region list) */ if ( FT_STREAM_SEEK( offset + region_offset ) ) @@ -564,13 +569,26 @@ goto Exit; itemStore->regionCount = region_count; - for ( i = 0; i < itemStore->regionCount; i++ ) + if ( FT_FRAME_ENTER( (FT_Long)region_count * axis_count * 6 ) ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " not enough data for variation regions\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bytes = stream->cursor; + + for ( i = 0; i < region_count; i++ ) { GX_AxisCoords axisCoords; if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, axis_count ) ) + { + FT_FRAME_EXIT(); goto Exit; + } axisCoords = itemStore->varRegionList[i].axisList; @@ -579,10 +597,9 @@ FT_Int start, peak, end; - if ( FT_READ_SHORT( start ) || - FT_READ_SHORT( peak ) || - FT_READ_SHORT( end ) ) - goto Exit; + start = FT_NEXT_SHORT( bytes ); + peak = FT_NEXT_SHORT( bytes ); + end = FT_NEXT_SHORT( bytes ); /* immediately tag invalid ranges with special peak = 0 */ if ( ( start < 0 && end > 0 ) || start > peak || peak > end ) @@ -594,6 +611,8 @@ } } + FT_FRAME_EXIT(); + /* end of region list parse */ /* use dataOffsetArray now to parse varData items */ @@ -625,7 +644,7 @@ /* check some data consistency */ if ( word_delta_count > region_idx_count ) { - FT_TRACE2(( "bad short count %d or region count %d\n", + FT_TRACE2(( "bad short count %d or region count %u\n", word_delta_count, region_idx_count )); error = FT_THROW( Invalid_Table ); @@ -634,7 +653,7 @@ if ( region_idx_count > itemStore->regionCount ) { - FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n", + FT_TRACE2(( "inconsistent regionCount %u in varData[%u]\n", region_idx_count, i )); error = FT_THROW( Invalid_Table ); @@ -648,20 +667,32 @@ varData->wordDeltaCount = word_delta_count; varData->longWords = long_words; + if ( FT_FRAME_ENTER( region_idx_count * 2 ) ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " not enough data for region indices\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bytes = stream->cursor; + for ( j = 0; j < varData->regionIdxCount; j++ ) { - if ( FT_READ_USHORT( varData->regionIndices[j] ) ) - goto Exit; + varData->regionIndices[j] = FT_NEXT_USHORT( bytes ); if ( varData->regionIndices[j] >= itemStore->regionCount ) { - FT_TRACE2(( "bad region index %d\n", + FT_TRACE2(( "bad region index %u\n", varData->regionIndices[j] )); + FT_FRAME_EXIT(); error = FT_THROW( Invalid_Table ); goto Exit; } } + FT_FRAME_EXIT(); + per_region_size = word_delta_count + region_idx_count; if ( long_words ) per_region_size *= 2; @@ -706,6 +737,7 @@ FT_UInt innerIndexMask; FT_ULong i; FT_UInt j; + FT_Byte* bytes; if ( FT_STREAM_SEEK( offset ) || @@ -757,6 +789,16 @@ if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) ) goto Exit; + if ( FT_FRAME_ENTER( map->mapCount * entrySize ) ) + { + FT_TRACE2(( "tt_var_load_delta_set_index_mapping:" + " invalid number of delta-set index mappings\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bytes = stream->cursor; + for ( i = 0; i < map->mapCount; i++ ) { FT_UInt mapData = 0; @@ -769,9 +811,7 @@ FT_Byte data; - if ( FT_READ_BYTE( data ) ) - goto Exit; - + data = FT_NEXT_BYTE( bytes ); mapData = ( mapData << 8 ) | data; } @@ -789,7 +829,7 @@ if ( outerIndex >= itemStore->dataCount ) { - FT_TRACE2(( "outerIndex[%ld] == %d out of range\n", + FT_TRACE2(( "outerIndex[%lu] == %u out of range\n", i, outerIndex )); error = FT_THROW( Invalid_Table ); @@ -802,7 +842,7 @@ if ( innerIndex >= itemStore->varData[outerIndex].itemCount ) { - FT_TRACE2(( "innerIndex[%ld] == %d out of range\n", + FT_TRACE2(( "innerIndex[%lu] == %u out of range\n", i, innerIndex )); error = FT_THROW( Invalid_Table ); @@ -812,6 +852,8 @@ map->innerIndex[i] = innerIndex; } + FT_FRAME_EXIT(); + Exit: return error; } @@ -965,28 +1007,181 @@ } + static FT_Fixed + tt_calculate_scalar( GX_AxisCoords axis, + FT_UInt axisCount, + FT_Fixed* normalizedcoords ) + { + FT_Fixed scalar = 0x10000L; + FT_UInt j; + + + /* Inner loop steps through axes in this region. */ + for ( j = 0; j < axisCount; j++, axis++ ) + { + FT_Fixed ncv = normalizedcoords[j]; + + + /* Compute the scalar contribution of this axis, */ + /* with peak of 0 used for invalid axes. */ + if ( axis->peakCoord == ncv || + axis->peakCoord == 0 ) + continue; + + /* Ignore this region if coordinates are out of range. */ + else if ( ncv <= axis->startCoord || + ncv >= axis->endCoord ) + { + scalar = 0; + break; + } + + /* Cumulative product of all the axis scalars. */ + else if ( ncv < axis->peakCoord ) + scalar = FT_MulDiv( scalar, + ncv - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else /* ncv > axis->peakCoord */ + scalar = FT_MulDiv( scalar, + axis->endCoord - ncv, + axis->endCoord - axis->peakCoord ); + + } /* per-axis loop */ + + return scalar; + } + + + static FT_Int64 + ft_mul_add_delta_scalar( FT_Int64 returnValue, + FT_Int32 delta, + FT_Int32 scalar ) + { + +#ifdef FT_INT64 + + return returnValue + (FT_Int64)delta * scalar; + +#else /* !FT_INT64 */ + + if ( (FT_UInt32)( delta + 0x8000 ) <= 0x20000 ) + { + /* Fast path: multiplication result fits into 32 bits. */ + + FT_Int32 lo = delta * scalar; + + + returnValue.lo += (FT_UInt32)lo; + + if ( returnValue.lo < (FT_UInt32)lo ) + returnValue.hi += ( lo < 0 ) ? 0 : 1; + + if ( lo < 0 ) + returnValue.hi -= 1; + + return returnValue; + } + else + { + /* Slow path: full 32x32 -> 64-bit signed multiplication. */ + + FT_Int64 product; + + /* Get absolute values. */ + FT_UInt32 a = ( delta < 0 ) ? -delta : delta; + FT_UInt32 b = ( scalar < 0 ) ? -scalar : scalar; + + /* Prepare unsigned multiplication. */ + FT_UInt32 a_lo = a & 0xFFFF; + FT_UInt32 a_hi = a >> 16; + + FT_UInt32 b_lo = b & 0xFFFF; + FT_UInt32 b_hi = b >> 16; + + /* Partial products. */ + FT_UInt32 p0 = a_lo * b_lo; + FT_UInt32 p1 = a_lo * b_hi; + FT_UInt32 p2 = a_hi * b_lo; + FT_UInt32 p3 = a_hi * b_hi; + + /* Combine: result = p3 << 32 + (p1 + p2) << 16 + p0 */ + FT_UInt32 mid = p1 + p2; + FT_UInt32 mid_carry = ( mid < p1 ); + + FT_UInt32 carry; + + + product.lo = ( mid << 16 ) + ( p0 & 0xFFFF ); + carry = ( product.lo < ( p0 & 0xFFFF ) ) ? 1 : 0; + product.hi = p3 + ( mid >> 16 ) + mid_carry + carry; + + /* If result should be negative, negate. */ + if ( ( delta < 0 ) ^ ( scalar < 0 ) ) + { + product.lo = ~product.lo + 1; + product.hi = ~product.hi + ( product.lo == 0 ? 1 : 0 ); + } + + /* Add to `returnValue`. */ + returnValue.lo += product.lo; + if ( returnValue.lo < product.lo ) + returnValue.hi++; + returnValue.hi += product.hi; + + return returnValue; + } + +#endif /* !FT_INT64 */ + + } + + + static FT_ItemVarDelta + ft_round_and_shift16( FT_Int64 returnValue ) + { + +#ifdef FT_INT64 + + return (FT_ItemVarDelta)( returnValue + 0x8000L ) >> 16; + +#else /* !FT_INT64 */ + + FT_UInt hi = returnValue.hi; + FT_UInt lo = returnValue.lo; + + FT_UInt delta; + + + /* Add 0x8000 to round. */ + lo += 0x8000; + if ( lo < 0x8000 ) /* overflow occurred */ + hi += 1; + + /* Shift right by 16 bits. */ + delta = ( hi << 16 ) | ( lo >> 16 ); + + return (FT_ItemVarDelta)delta; + +#endif /* !FT_INT64 */ + + } + + FT_LOCAL_DEF( FT_ItemVarDelta ) tt_var_get_item_delta( FT_Face face, /* TT_Face */ GX_ItemVarStore itemStore, FT_UInt outerIndex, FT_UInt innerIndex ) { - TT_Face ttface = (TT_Face)face; - FT_Stream stream = FT_FACE_STREAM( face ); - FT_Memory memory = stream->memory; - FT_Error error = FT_Err_Ok; + TT_Face ttface = (TT_Face)face; - GX_ItemVarData varData; - FT_ItemVarDelta* deltaSet = NULL; - FT_ItemVarDelta deltaSetStack[16]; + GX_ItemVarData varData; - FT_Fixed* scalars = NULL; - FT_Fixed scalarsStack[16]; - - FT_UInt master, j; - FT_ItemVarDelta returnValue = 0; - FT_UInt per_region_size; - FT_Byte* bytes; + FT_UInt master; + FT_Int64 returnValue = FT_INT64_ZERO; + FT_UInt shift_base = 1; + FT_UInt per_region_size; + FT_Byte* bytes; if ( !ttface->blend || !ttface->blend->normalizedcoords ) @@ -1011,113 +1206,63 @@ if ( varData->regionIdxCount == 0 ) return 0; /* Avoid "applying zero offset to null pointer". */ - if ( varData->regionIdxCount < 16 ) - { - deltaSet = deltaSetStack; - scalars = scalarsStack; - } - else - { - if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) ) - goto Exit; - if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) ) - goto Exit; - } - /* Parse delta set. */ /* */ /* Deltas are (word_delta_count + region_idx_count) bytes each */ /* if `longWords` isn't set, and twice as much otherwise. */ per_region_size = varData->wordDeltaCount + varData->regionIdxCount; if ( varData->longWords ) + { + shift_base = 2; per_region_size *= 2; + } bytes = varData->deltaSet + per_region_size * innerIndex; - if ( varData->longWords ) - { - for ( master = 0; master < varData->wordDeltaCount; master++ ) - deltaSet[master] = FT_NEXT_LONG( bytes ); - for ( ; master < varData->regionIdxCount; master++ ) - deltaSet[master] = FT_NEXT_SHORT( bytes ); - } - else - { - for ( master = 0; master < varData->wordDeltaCount; master++ ) - deltaSet[master] = FT_NEXT_SHORT( bytes ); - for ( ; master < varData->regionIdxCount; master++ ) - deltaSet[master] = FT_NEXT_CHAR( bytes ); - } - /* outer loop steps through master designs to be blended */ for ( master = 0; master < varData->regionIdxCount; master++ ) { - FT_Fixed scalar = 0x10000L; - FT_UInt regionIndex = varData->regionIndices[master]; + FT_UInt regionIndex = varData->regionIndices[master]; GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList; + FT_Fixed scalar = tt_calculate_scalar( + axis, + itemStore->axisCount, + ttface->blend->normalizedcoords ); - /* inner loop steps through axes in this region */ - for ( j = 0; j < itemStore->axisCount; j++, axis++ ) + + if ( scalar ) { - FT_Fixed ncv = ttface->blend->normalizedcoords[j]; + FT_Int delta; - /* compute the scalar contribution of this axis */ - /* with peak of 0 used for invalid axes */ - if ( axis->peakCoord == ncv || - axis->peakCoord == 0 ) - continue; - - /* ignore this region if coords are out of range */ - else if ( ncv <= axis->startCoord || - ncv >= axis->endCoord ) + if ( varData->longWords ) { - scalar = 0; - break; + if ( master < varData->wordDeltaCount ) + delta = FT_NEXT_LONG( bytes ); + else + delta = FT_NEXT_SHORT( bytes ); + } + else + { + if ( master < varData->wordDeltaCount ) + delta = FT_NEXT_SHORT( bytes ); + else + delta = FT_NEXT_CHAR( bytes ); } - /* cumulative product of all the axis scalars */ - else if ( ncv < axis->peakCoord ) - scalar = FT_MulDiv( scalar, - ncv - axis->startCoord, - axis->peakCoord - axis->startCoord ); - else /* ncv > axis->peakCoord */ - scalar = FT_MulDiv( scalar, - axis->endCoord - ncv, - axis->endCoord - axis->peakCoord ); - - } /* per-axis loop */ - - scalars[master] = scalar; + returnValue = ft_mul_add_delta_scalar( returnValue, delta, scalar ); + } + else + { + /* Branch-free, yay. */ + bytes += shift_base << ( master < varData->wordDeltaCount ); + } } /* per-region loop */ - - /* Compute the scaled delta for this region. - * - * From: https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables: - * - * `Fixed` is a 32-bit (16.16) type and, in the general case, requires - * 32-bit deltas. As described above, the `DeltaSet` record can - * accommodate deltas that are, logically, either 16-bit or 32-bit. - * When scaled deltas are applied to `Fixed` values, the `Fixed` value - * is treated like a 32-bit integer. - * - * `FT_MulAddFix` internally uses 64-bit precision; it thus can handle - * deltas ranging from small 8-bit to large 32-bit values that are - * applied to 16.16 `FT_Fixed` / OpenType `Fixed` values. - */ - returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount ); - - Exit: - if ( scalars != scalarsStack ) - FT_FREE( scalars ); - if ( deltaSet != deltaSetStack ) - FT_FREE( deltaSet ); - - return returnValue; + return ft_round_and_shift16( returnValue ); } @@ -1643,6 +1788,7 @@ GX_Blend blend = face->blend; FT_Error error; FT_UInt i, j; + FT_Byte* bytes; FT_ULong table_len; FT_ULong gvar_start; FT_ULong offsetToData; @@ -1734,6 +1880,8 @@ if ( FT_FRAME_ENTER( offsets_len ) ) goto Exit; + bytes = stream->cursor; + /* offsets (one more offset than glyphs, to mark size of last) */ if ( FT_QNEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) ) goto Fail2; @@ -1744,16 +1892,24 @@ FT_ULong max_offset = 0; + if ( stream->limit - stream->cursor < gvar_head.glyphCount * 4 ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset not enough\n" )); + error = FT_THROW( Invalid_Table ); + goto Fail; + } + for ( i = 0; i <= gvar_head.glyphCount; i++ ) { - blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); + blend->glyphoffsets[i] = offsetToData + FT_NEXT_ULONG( bytes ); if ( max_offset <= blend->glyphoffsets[i] ) max_offset = blend->glyphoffsets[i]; else { FT_TRACE2(( "ft_var_load_gvar:" - " glyph variation data offset %d not monotonic\n", + " glyph variation data offset %u not monotonic\n", i )); blend->glyphoffsets[i] = max_offset; } @@ -1762,7 +1918,7 @@ if ( limit < blend->glyphoffsets[i] ) { FT_TRACE2(( "ft_var_load_gvar:" - " glyph variation data offset %d out of range\n", + " glyph variation data offset %u out of range\n", i )); blend->glyphoffsets[i] = limit; } @@ -1774,16 +1930,24 @@ FT_ULong max_offset = 0; + if ( stream->limit - stream->cursor < gvar_head.glyphCount * 2 ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset not enough\n" )); + error = FT_THROW( Invalid_Table ); + goto Fail; + } + for ( i = 0; i <= gvar_head.glyphCount; i++ ) { - blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; + blend->glyphoffsets[i] = offsetToData + FT_NEXT_USHORT( bytes ) * 2; if ( max_offset <= blend->glyphoffsets[i] ) max_offset = blend->glyphoffsets[i]; else { FT_TRACE2(( "ft_var_load_gvar:" - " glyph variation data offset %d not monotonic\n", + " glyph variation data offset %u not monotonic\n", i )); blend->glyphoffsets[i] = max_offset; } @@ -1792,7 +1956,7 @@ if ( limit < blend->glyphoffsets[i] ) { FT_TRACE2(( "ft_var_load_gvar:" - " glyph variation data offset %d out of range\n", + " glyph variation data offset %u out of range\n", i )); blend->glyphoffsets[i] = limit; } @@ -1814,6 +1978,8 @@ goto Fail; } + bytes = stream->cursor; + if ( FT_QNEW_ARRAY( blend->tuplecoords, gvar_head.axisCount * gvar_head.globalCoordCount ) ) goto Fail2; @@ -1824,13 +1990,17 @@ for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ ) { blend->tuplecoords[i * gvar_head.axisCount + j] = - FT_fdot14ToFixed( FT_GET_SHORT() ); + FT_fdot14ToFixed( FT_NEXT_SHORT( bytes ) ); FT_TRACE5(( "%.5f ", (double)blend->tuplecoords[i * gvar_head.axisCount + j] / 65536 )); } FT_TRACE5(( "]\n" )); } + if ( FT_NEW_ARRAY( blend->tuplescalars, + gvar_head.globalCoordCount ) ) + goto Fail2; + blend->tuplecount = gvar_head.globalCoordCount; FT_TRACE5(( "\n" )); @@ -1896,15 +2066,25 @@ for ( i = 0; i < blend->num_axis; i++ ) { - FT_Fixed ncv = blend->normalizedcoords[i]; + FT_Fixed ncv; - FT_TRACE6(( " axis %d coordinate %.5f:\n", i, (double)ncv / 65536 )); + if ( tuple_coords[i] == 0 ) + { + FT_TRACE6(( " tuple coordinate is zero, ignore\n" )); + continue; + } - /* It's not clear why (for intermediate tuples) we don't need */ - /* to check against start/end -- the documentation says we don't. */ - /* Similarly, it's unclear why we don't need to scale along the */ - /* axis. */ + ncv = blend->normalizedcoords[i]; + + FT_TRACE6(( " axis %u coordinate %.5f:\n", i, (double)ncv / 65536 )); + + if ( ncv == 0 ) + { + FT_TRACE6(( " axis coordinate is zero, stop\n" )); + apply = 0; + break; + } if ( tuple_coords[i] == ncv ) { @@ -1914,12 +2094,6 @@ continue; } - if ( tuple_coords[i] == 0 ) - { - FT_TRACE6(( " tuple coordinate is zero, ignore\n" )); - continue; - } - if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) { /* not an intermediate tuple */ @@ -2001,7 +2175,7 @@ if ( num_coords > mmvar->num_axis ) { FT_TRACE2(( "ft_var_to_normalized:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", mmvar->num_axis, num_coords )); num_coords = mmvar->num_axis; } @@ -2016,7 +2190,7 @@ FT_Fixed coord = coords[i]; - FT_TRACE5(( " %d: %.5f\n", i, (double)coord / 65536 )); + FT_TRACE5(( " %u: %.5f\n", i, (double)coord / 65536 )); if ( coord > a->maximum || coord < a->minimum ) { FT_TRACE1(( "ft_var_to_normalized: design coordinate %.5f\n", @@ -2156,7 +2330,7 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "ft_var_to_design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } @@ -2516,7 +2690,7 @@ " minimum default maximum flags\n" )); /* " XXXX.XXXXX XXXX.XXXXX XXXX.XXXXX 0xXXXX" */ - FT_TRACE5(( " %3d `%s'" + FT_TRACE5(( " %3u `%s'" " %10.5f %10.5f %10.5f 0x%04X%s\n", i, a->name, @@ -2608,7 +2782,7 @@ (void)FT_STREAM_SEEK( pos ); - FT_TRACE5(( " named instance %d (%s%s%s, %s%s%s)\n", + FT_TRACE5(( " named instance %u (%s%s%s, %s%s%s)\n", i, strname ? "name: `" : "", strname ? strname : "unnamed", @@ -2636,7 +2810,7 @@ FT_UInt strid = ~0U; - /* The default instance is missing in array the */ + /* The default instance is missing in the array */ /* of named instances; try to synthesize an entry. */ /* If this fails, `default_named_instance` remains */ /* at value zero, which doesn't do any harm. */ @@ -2766,10 +2940,18 @@ } manageCvt; - face->doblend = FALSE; - if ( !face->blend ) { + face->doblend = FALSE; + for ( i = 0; i < num_coords; i++ ) + if ( coords[i] ) + { + face->doblend = TRUE; + break; + } + if ( !face->doblend ) + goto Exit; + if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) ) goto Exit; } @@ -2780,7 +2962,7 @@ if ( num_coords > mmvar->num_axis ) { FT_TRACE2(( "TT_Set_MM_Blend:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", mmvar->num_axis, num_coords )); num_coords = mmvar->num_axis; } @@ -2882,11 +3064,7 @@ /* return value -1 indicates `no change' */ if ( !have_diff ) - { - face->doblend = TRUE; - return -1; - } for ( ; i < mmvar->num_axis; i++ ) { @@ -2915,7 +3093,15 @@ blend->normalizedcoords, blend->coords ); - face->doblend = TRUE; + face->doblend = FALSE; + for ( i = 0; i < blend->num_axis; i++ ) + { + if ( blend->normalizedcoords[i] ) + { + face->doblend = TRUE; + break; + } + } if ( face->cvt ) { @@ -2941,6 +3127,9 @@ } } + for ( i = 0 ; i < blend->tuplecount ; i++ ) + blend->tuplescalars[i] = (FT_Fixed)-0x20000L; + Exit: return error; } @@ -2980,7 +3169,24 @@ FT_UInt num_coords, FT_Fixed* coords ) { - return tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 ); + FT_Error error; + + + error = tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 ); + if ( error == FT_Err_Ok ) + { + FT_UInt i; + + + for ( i = 0; i < num_coords; i++ ) + if ( coords[i] ) + { + error = -2; /* -2 means is_variable. */ + break; + } + } + + return error; } @@ -3043,7 +3249,7 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "TT_Get_MM_Blend:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } @@ -3125,7 +3331,7 @@ if ( num_coords > mmvar->num_axis ) { FT_TRACE2(( "TT_Set_Var_Design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", mmvar->num_axis, num_coords )); num_coords = mmvar->num_axis; } @@ -3201,6 +3407,15 @@ if ( error ) goto Exit; + for ( i = 0; i < num_coords; i++ ) + { + if ( normalized[i] ) + { + error = -2; /* -2 means is_variable. */ + break; + } + } + Exit: FT_FREE( normalized ); return error; @@ -3237,10 +3452,12 @@ FT_UInt num_coords, FT_Fixed* coords ) { - TT_Face ttface = (TT_Face)face; - FT_Error error = FT_Err_Ok; - GX_Blend blend; - FT_UInt i, nc; + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_Var_Axis* a; + FT_UInt i, nc; if ( !ttface->blend ) @@ -3263,24 +3480,26 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "TT_Get_Var_Design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } + mmvar = blend->mmvar; + a = mmvar->axis; if ( ttface->doblend ) { - for ( i = 0; i < nc; i++ ) + for ( i = 0; i < nc; i++, a++ ) coords[i] = blend->coords[i]; } else { - for ( i = 0; i < nc; i++ ) - coords[i] = 0; + for ( i = 0; i < nc; i++, a++ ) + coords[i] = a->def; } - for ( ; i < num_coords; i++ ) - coords[i] = 0; + for ( ; i < num_coords; i++, a++ ) + coords[i] = a->def; return FT_Err_Ok; } @@ -3373,6 +3592,9 @@ error = TT_Set_Var_Design( face, 0, NULL ); } + if ( error == -1 || error == -2 ) + error = FT_Err_Ok; + Exit: return error; } @@ -3591,7 +3813,7 @@ FT_Stream_SeekSet( stream, here ); } - FT_TRACE5(( "cvar: there %s %d tuple%s:\n", + FT_TRACE5(( "cvar: there %s %u tuple%s:\n", ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", tupleCount & GX_TC_TUPLE_COUNT_MASK, ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); @@ -3610,7 +3832,7 @@ FT_Fixed apply; - FT_TRACE6(( " tuple %d:\n", i )); + FT_TRACE6(( " tuple %u:\n", i )); tupleDataSize = FT_GET_USHORT(); tupleIndex = FT_GET_USHORT(); @@ -3676,7 +3898,7 @@ if ( !points || !deltas ) ; /* failure, ignore it */ - else if ( localpoints == ALL_POINTS ) + else if ( points == ALL_POINTS ) { #ifdef FT_DEBUG_LEVEL_TRACE int count = 0; @@ -3697,7 +3919,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( old_cvt_delta != cvt_deltas[j] ) { - FT_TRACE7(( " %d: %f -> %f\n", + FT_TRACE7(( " %u: %f -> %f\n", j, (double)( FT_fdot6ToFixed( face->cvt[j] ) + old_cvt_delta ) / 65536, @@ -4027,7 +4249,7 @@ FT_Outline* outline, FT_Vector* unrounded ) { - FT_Error error; + FT_Error error = FT_Err_Ok; TT_Face face = loader->face; FT_Stream stream = face->root.stream; FT_Memory memory = stream->memory; @@ -4047,6 +4269,15 @@ FT_ULong here; FT_UInt i, j; + FT_UInt peak_coords_size; + FT_UInt point_deltas_x_size; + FT_UInt points_org_size; + FT_UInt points_out_size; + FT_UInt has_delta_size; + FT_UInt pool_size; + FT_Byte* pool = NULL; + FT_Byte* p; + FT_Fixed* peak_coords = NULL; FT_Fixed* tuple_coords; FT_Fixed* im_start_coords; @@ -4067,21 +4298,24 @@ FT_Fixed* point_deltas_y = NULL; - if ( !face->doblend || !blend ) - return FT_THROW( Invalid_Argument ); - for ( i = 0; i < n_points; i++ ) { unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x ); unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y ); } + if ( !face->doblend ) + goto Exit; + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + if ( glyph_index >= blend->gv_glyphcnt || blend->glyphoffsets[glyph_index] == blend->glyphoffsets[glyph_index + 1] ) { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" - " no variation data for glyph %d\n", glyph_index )); + " no variation data for glyph %u\n", glyph_index )); return FT_Err_Ok; } @@ -4125,18 +4359,41 @@ FT_Stream_SeekSet( stream, here ); } - FT_TRACE5(( "gvar: there %s %d tuple%s:\n", + FT_TRACE5(( "gvar: there %s %u tuple%s:\n", ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", tupleCount & GX_TC_TUPLE_COUNT_MASK, ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); - if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) || - FT_NEW_ARRAY( point_deltas_x, 2 * n_points ) || - FT_QNEW_ARRAY( points_org, n_points ) || - FT_QNEW_ARRAY( points_out, n_points ) || - FT_QNEW_ARRAY( has_delta, n_points ) ) + peak_coords_size = ALIGN_SIZE( 3 * blend->num_axis * + sizeof ( *peak_coords ) ); + point_deltas_x_size = ALIGN_SIZE( 2 * n_points * + sizeof ( *point_deltas_x ) ); + points_org_size = ALIGN_SIZE( n_points * sizeof ( *points_org ) ); + points_out_size = ALIGN_SIZE( n_points * sizeof ( *points_out ) ); + has_delta_size = ALIGN_SIZE( n_points * sizeof ( *has_delta ) ); + + pool_size = peak_coords_size + + point_deltas_x_size + + points_org_size + + points_out_size + + has_delta_size; + + if ( FT_ALLOC( pool, pool_size ) ) goto Exit; + p = pool; + peak_coords = (FT_Fixed*)p; + p += peak_coords_size; + point_deltas_x = (FT_Fixed*)p; + p += point_deltas_x_size; + points_org = (FT_Vector*)p; + p += points_org_size; + points_out = (FT_Vector*)p; + p += points_out_size; + has_delta = (FT_Bool*)p; + + FT_ARRAY_ZERO( point_deltas_x, 2 * n_points ); + im_start_coords = peak_coords + blend->num_axis; im_end_coords = im_start_coords + blend->num_axis; point_deltas_y = point_deltas_x + n_points; @@ -4147,27 +4404,70 @@ points_org[j].y = FT_intToFixed( outline->points[j].y ); } - for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) + p = stream->cursor; + + tupleCount &= GX_TC_TUPLE_COUNT_MASK; + for ( i = 0; i < tupleCount; i++ ) { - FT_UInt tupleDataSize; - FT_UInt tupleIndex; - FT_Fixed apply; + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + FT_Fixed* tupleScalars; - FT_TRACE6(( " tuple %d:\n", i )); + FT_TRACE6(( " tuple %u:\n", i )); - tupleDataSize = FT_GET_USHORT(); - tupleIndex = FT_GET_USHORT(); + tupleScalars = blend->tuplescalars; + + /* Enter frame for four bytes. */ + if ( 4 > stream->limit - p ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + tupleDataSize = FT_NEXT_USHORT( p ); + tupleIndex = FT_NEXT_USHORT( p ); + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + tupleScalars = NULL; if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { + if ( 2 * blend->num_axis > (FT_UInt)( stream->limit - p ) ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + for ( j = 0; j < blend->num_axis; j++ ) - peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + peak_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) ); + tuple_coords = peak_coords; + tupleScalars = NULL; } else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) + { + FT_Fixed scalar = + tupleScalars + ? tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] + : (FT_Fixed)-0x20000; + + + if ( scalar != (FT_Fixed)-0x20000 ) + { + apply = scalar; + goto apply_found; + } + tuple_coords = blend->tuplecoords + - ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis; + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * + blend->num_axis; + } else { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" @@ -4179,10 +4479,18 @@ if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { + if ( 4 * blend->num_axis > (FT_UInt)( stream->limit - p ) ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + for ( j = 0; j < blend->num_axis; j++ ) - im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + im_start_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) ); for ( j = 0; j < blend->num_axis; j++ ) - im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + im_end_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) ); } apply = ft_var_apply_tuple( blend, @@ -4191,6 +4499,11 @@ im_start_coords, im_end_coords ); + if ( tupleScalars ) + tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] = apply; + + apply_found: + if ( apply == 0 ) /* tuple isn't active for our blend */ { offsetToData += tupleDataSize; @@ -4247,7 +4560,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( point_delta_x || point_delta_y ) { - FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + FT_TRACE7(( " %u: (%f, %f) -> (%f, %f)\n", j, (double)( FT_intToFixed( outline->points[j].x ) + old_point_delta_x ) / 65536, @@ -4321,7 +4634,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( point_delta_x || point_delta_y ) { - FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + FT_TRACE7(( " %u: (%f, %f) -> (%f, %f)\n", j, (double)( FT_intToFixed( outline->points[j].x ) + old_point_delta_x ) / 65536, @@ -4402,11 +4715,7 @@ Exit: if ( sharedpoints != ALL_POINTS ) FT_FREE( sharedpoints ); - FT_FREE( points_org ); - FT_FREE( points_out ); - FT_FREE( has_delta ); - FT_FREE( peak_coords ); - FT_FREE( point_deltas_x ); + FT_FREE( pool ); FExit: FT_FRAME_EXIT(); @@ -4577,6 +4886,7 @@ FT_FREE( blend->mvar_table ); } + FT_FREE( blend->tuplescalars ); FT_FREE( blend->tuplecoords ); FT_FREE( blend->glyphoffsets ); FT_FREE( blend ); diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h index 9326011e3a2..568c8027bbf 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader (specification) * - * Copyright (C) 2004-2024 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, Werner Lemberg and George Williams. * * This file is part of the FreeType project, and may only be used, @@ -255,6 +255,10 @@ FT_BEGIN_HEADER * A two-dimensional array that holds the shared tuple coordinates * in the `gvar' table. * + * tuplescalars :: + * A one-dimensional array that holds the shared tuple + * scalars in the `gvar' table for current face coordinates. + * * gv_glyphcnt :: * The number of glyphs handled in the `gvar' table. * @@ -293,6 +297,7 @@ FT_BEGIN_HEADER FT_UInt tuplecount; FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ + FT_Fixed* tuplescalars; /* tuplescalars[tuplecount] */ FT_UInt gv_glyphcnt; FT_ULong* glyphoffsets; /* glyphoffsets[gv_glyphcnt + 1] */ diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c index 951891dbf51..7b26c9a9df2 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -27,6 +27,8 @@ #include #include +#ifdef TT_USE_BYTECODE_INTERPRETER + #include "ttinterp.h" #include "tterrors.h" #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT @@ -34,9 +36,6 @@ #endif -#ifdef TT_USE_BYTECODE_INTERPRETER - - /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit @@ -89,6 +88,32 @@ #define FAILURE 1 + /* The default value for `scan_control' is documented as FALSE in the */ + /* TrueType specification. This is confusing since it implies a */ + /* Boolean value. However, this is not the case, thus both the */ + /* default values of our `scan_type' and `scan_control' fields (which */ + /* the documentation's `scan_control' variable is split into) are */ + /* zero. */ + /* */ + /* The rounding compensation should logically belong here but poorly */ + /* described in the OpenType specs. It was probably important in the */ + /* days of dot matrix printers. The values are referenced by color */ + /* as Gray, Black, and White in order. The Apple specification says */ + /* that the Gray compensation is always zero. The fourth value is */ + /* not described at all, but Greg says that it is the same as Gray. */ + /* FreeType sets all compensation values to zero. */ + + const TT_GraphicsState tt_default_graphics_state = + { + 0, 0, 0, 1, 1, 1, + { 0x4000, 0 }, { 0x4000, 0 }, { 0x4000, 0 }, + 1, 1, { 0, 0, 0, 0 }, + + 64, 68, 0, 0, 9, 3, + TRUE, 0, FALSE, 0 + }; + + /************************************************************************** * * CODERANGE FUNCTIONS @@ -96,53 +121,6 @@ */ - /************************************************************************** - * - * @Function: - * TT_Goto_CodeRange - * - * @Description: - * Switches to a new code range (updates the code related elements in - * `exec', and `IP'). - * - * @Input: - * range :: - * The new execution code range. - * - * IP :: - * The new IP in the new code range. - * - * @InOut: - * exec :: - * The target execution context. - */ - FT_LOCAL_DEF( void ) - TT_Goto_CodeRange( TT_ExecContext exec, - FT_Int range, - FT_Long IP ) - { - TT_CodeRange* coderange; - - - FT_ASSERT( range >= 1 && range <= 3 ); - - coderange = &exec->codeRangeTable[range - 1]; - - FT_ASSERT( coderange->base ); - - /* NOTE: Because the last instruction of a program may be a CALL */ - /* which will return to the first byte *after* the code */ - /* range, we test for IP <= Size instead of IP < Size. */ - /* */ - FT_ASSERT( IP <= coderange->size ); - - exec->code = coderange->base; - exec->codeSize = coderange->size; - exec->IP = IP; - exec->curRange = range; - } - - /************************************************************************** * * @Function: @@ -168,13 +146,19 @@ FT_LOCAL_DEF( void ) TT_Set_CodeRange( TT_ExecContext exec, FT_Int range, - void* base, + FT_Byte* base, FT_Long length ) { FT_ASSERT( range >= 1 && range <= 3 ); - exec->codeRangeTable[range - 1].base = (FT_Byte*)base; + exec->codeRangeTable[range - 1].base = base; exec->codeRangeTable[range - 1].size = length; + + exec->code = base; + exec->codeSize = length; + exec->IP = 0; + exec->curRange = range; + exec->iniRange = range; } @@ -224,9 +208,6 @@ * exec :: * A handle to the target execution context. * - * memory :: - * A handle to the parent memory object. - * * @Note: * Only the glyph loader and debugger should call this function. */ @@ -240,10 +221,6 @@ exec->maxPoints = 0; exec->maxContours = 0; - /* free stack */ - FT_FREE( exec->stack ); - exec->stackSize = 0; - /* free glyf cvt working area */ FT_FREE( exec->glyfCvt ); exec->glyfCvtSize = 0; @@ -300,72 +277,26 @@ TT_Face face, TT_Size size ) { - FT_Int i; - TT_MaxProfile* maxp; - FT_Error error; - FT_Memory memory = exec->memory; + FT_Memory memory = exec->memory; exec->face = face; - maxp = &face->max_profile; exec->size = size; - if ( size ) - { - exec->numFDefs = size->num_function_defs; - exec->maxFDefs = size->max_function_defs; - exec->numIDefs = size->num_instruction_defs; - exec->maxIDefs = size->max_instruction_defs; - exec->FDefs = size->function_defs; - exec->IDefs = size->instruction_defs; - exec->pointSize = size->point_size; - exec->tt_metrics = size->ttmetrics; - exec->metrics = *size->metrics; - - exec->maxFunc = size->max_func; - exec->maxIns = size->max_ins; - - for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) - exec->codeRangeTable[i] = size->codeRangeTable[i]; - - /* set graphics state */ - exec->GS = size->GS; - - exec->cvtSize = size->cvt_size; - exec->cvt = size->cvt; - - exec->storeSize = size->storage_size; - exec->storage = size->storage; - - exec->twilight = size->twilight; - - /* In case of multi-threading it can happen that the old size object */ - /* no longer exists, thus we must clear all glyph zone references. */ - FT_ZERO( &exec->zp0 ); - exec->zp1 = exec->zp0; - exec->zp2 = exec->zp0; - } - - /* XXX: We reserve a little more elements on the stack to deal safely */ - /* with broken fonts like arialbs, courbs, timesbs, etc. */ - if ( FT_QRENEW_ARRAY( exec->stack, - exec->stackSize, - maxp->maxStackElements + 32 ) ) - return error; - exec->stackSize = maxp->maxStackElements + 32; + /* CVT and storage are not persistent in FreeType */ + /* reset them after they might have been modifief */ + exec->storage = exec->stack + exec->stackSize; + exec->cvt = exec->storage + exec->storeSize; /* free previous glyph code range */ FT_FREE( exec->glyphIns ); exec->glyphSize = 0; - exec->pts.n_points = 0; - exec->pts.n_contours = 0; + exec->pointSize = size->point_size; + exec->tt_metrics = size->ttmetrics; + exec->metrics = *size->metrics; - exec->zp1 = exec->pts; - exec->zp2 = exec->pts; - exec->zp0 = exec->pts; - - exec->instruction_trap = FALSE; + exec->twilight = size->twilight; return FT_Err_Ok; } @@ -394,89 +325,22 @@ TT_Save_Context( TT_ExecContext exec, TT_Size size ) { - FT_Int i; + /* UNDOCUMENTED! */ + /* Only these GS values can be modified by the CVT program. */ - - /* XXX: Will probably disappear soon with all the code range */ - /* management, which is now rather obsolete. */ - /* */ - size->num_function_defs = exec->numFDefs; - size->num_instruction_defs = exec->numIDefs; - - size->max_func = exec->maxFunc; - size->max_ins = exec->maxIns; - - for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) - size->codeRangeTable[i] = exec->codeRangeTable[i]; + size->GS.minimum_distance = exec->GS.minimum_distance; + size->GS.control_value_cutin = exec->GS.control_value_cutin; + size->GS.single_width_cutin = exec->GS.single_width_cutin; + size->GS.single_width_value = exec->GS.single_width_value; + size->GS.delta_base = exec->GS.delta_base; + size->GS.delta_shift = exec->GS.delta_shift; + size->GS.auto_flip = exec->GS.auto_flip; + size->GS.instruct_control = exec->GS.instruct_control; + size->GS.scan_control = exec->GS.scan_control; + size->GS.scan_type = exec->GS.scan_type; } - /************************************************************************** - * - * @Function: - * TT_Run_Context - * - * @Description: - * Executes one or more instructions in the execution context. - * - * @Input: - * exec :: - * A handle to the target execution context. - * - * @Return: - * TrueType error code. 0 means success. - */ - FT_LOCAL_DEF( FT_Error ) - TT_Run_Context( TT_ExecContext exec ) - { - TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ); - - exec->zp0 = exec->pts; - exec->zp1 = exec->pts; - exec->zp2 = exec->pts; - - exec->GS.gep0 = 1; - exec->GS.gep1 = 1; - exec->GS.gep2 = 1; - - exec->GS.projVector.x = 0x4000; - exec->GS.projVector.y = 0x0000; - - exec->GS.freeVector = exec->GS.projVector; - exec->GS.dualVector = exec->GS.projVector; - - exec->GS.round_state = 1; - exec->GS.loop = 1; - - /* some glyphs leave something on the stack. so we clean it */ - /* before a new execution. */ - exec->top = 0; - exec->callTop = 0; - - return exec->face->interpreter( exec ); - } - - - /* The default value for `scan_control' is documented as FALSE in the */ - /* TrueType specification. This is confusing since it implies a */ - /* Boolean value. However, this is not the case, thus both the */ - /* default values of our `scan_type' and `scan_control' fields (which */ - /* the documentation's `scan_control' variable is split into) are */ - /* zero. */ - - const TT_GraphicsState tt_default_graphics_state = - { - 0, 0, 0, - { 0x4000, 0 }, - { 0x4000, 0 }, - { 0x4000, 0 }, - - 1, 64, 1, - TRUE, 68, 0, 0, 9, 3, - 0, FALSE, 0, 1, 1, 1 - }; - - /* documentation is in ttinterp.h */ FT_EXPORT_DEF( TT_ExecContext ) @@ -485,7 +349,8 @@ FT_Memory memory; FT_Error error; - TT_ExecContext exec = NULL; + TT_ExecContext exec = NULL; + FT_DebugHook_Func interp; if ( !driver ) @@ -497,6 +362,15 @@ if ( FT_NEW( exec ) ) goto Fail; + /* set `exec->interpreter' according to the debug hook present, */ + /* which is used by 'ttdebug'. */ + interp = driver->root.root.library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; + + if ( interp ) + exec->interpreter = (TT_Interpreter)interp; + else + exec->interpreter = (TT_Interpreter)TT_RunIns; + /* create callStack here, other allocations delayed */ exec->memory = memory; exec->callSize = 32; @@ -1160,20 +1034,35 @@ #undef PACK -#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER +#ifdef FT_INT64 + +#define TT_MulFix14( a, b ) TT_MulFix14_64( a, b ) + + static inline FT_F26Dot6 + TT_MulFix14_64( FT_F26Dot6 a, + FT_F2Dot14 b ) + { + FT_Int64 ab = MUL_INT64( a, b ); + + + ab = ADD_INT64( ab, 0x2000 + ( ab >> 63 ) ); /* rounding phase */ + + return (FT_F26Dot6)( ab >> 14 ); + } + +#elif !defined( FT_CONFIG_OPTION_NO_ASSEMBLER ) #if defined( __arm__ ) && \ ( defined( __thumb2__ ) || !defined( __thumb__ ) ) #define TT_MulFix14 TT_MulFix14_arm - static FT_Int32 + static __inline FT_Int32 TT_MulFix14_arm( FT_Int32 a, - FT_Int b ) + FT_Int32 b ) { FT_Int32 t, t2; - #if defined( __CC_ARM ) || defined( __ARMCC__ ) __asm @@ -1199,8 +1088,8 @@ #endif "adds %1, %1, %0\n\t" /* %1 += %0 */ "adc %2, %2, #0\n\t" /* %2 += carry */ - "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */ - "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */ + "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 14 */ + "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 18 */ : "=r"(a), "=&r"(t2), "=&r"(t) : "r"(a), "r"(b) : "cc" ); @@ -1210,49 +1099,60 @@ return a; } -#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */ +#elif defined( __i386__ ) || defined( _M_IX86 ) -#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ +#define TT_MulFix14 TT_MulFix14_i386 + /* documentation is in freetype.h */ -#if defined( __GNUC__ ) && \ - ( defined( __i386__ ) || defined( __x86_64__ ) ) - -#define TT_MulFix14 TT_MulFix14_long_long - - /* Temporarily disable the warning that C90 doesn't support `long long'. */ -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic push -#endif -#pragma GCC diagnostic ignored "-Wlong-long" - - /* This is declared `noinline' because inlining the function results */ - /* in slower code. The `pure' attribute indicates that the result */ - /* only depends on the parameters. */ - static __attribute__(( noinline )) - __attribute__(( pure )) FT_Int32 - TT_MulFix14_long_long( FT_Int32 a, - FT_Int b ) + static __inline FT_Int32 + TT_MulFixi14_i386( FT_Int32 a, + FT_Int32 b ) { + FT_Int32 result; - long long ret = (long long)a * b; +#if defined( __GNUC__ ) - /* The following line assumes that right shifting of signed values */ - /* will actually preserve the sign bit. The exact behaviour is */ - /* undefined, but this is true on x86 and x86_64. */ - long long tmp = ret >> 63; + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x2000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $14, %%eax\n" + "shll $18, %%edx\n" + "addl %%edx, %%eax\n" + : "=a"(result), "=d"(b) + : "a"(a), "d"(b) + : "%ecx", "cc" ); +#elif defined( _MSC_VER) - ret += 0x2000 + tmp; + __asm + { + mov eax, a + mov edx, b + imul edx + mov ecx, edx + sar ecx, 31 + add ecx, 2000h + add eax, ecx + adc edx, 0 + shr eax, 14 + shl edx, 18 + add eax, edx + mov result, eax + } - return (FT_Int32)( ret >> 14 ); +#endif + + return result; } -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic pop -#endif +#endif /* __i386__ || _M_IX86 */ -#endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */ +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ #ifndef TT_MulFix14 @@ -1262,92 +1162,59 @@ /* for platforms where sizeof(int) == 2. */ static FT_Int32 TT_MulFix14( FT_Int32 a, - FT_Int b ) + FT_Int16 b ) { - FT_Int32 sign; - FT_UInt32 ah, al, mid, lo, hi; + FT_Int32 m, hi; + FT_UInt32 l, lo; - sign = a ^ b; + /* compute a*b as 64-bit (hi_lo) value */ + l = (FT_UInt32)( ( a & 0xFFFFU ) * b ); + m = ( a >> 16 ) * b; - if ( a < 0 ) - a = -a; - if ( b < 0 ) - b = -b; + lo = l + ( (FT_UInt32)m << 16 ); + hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l ); - ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU ); - al = (FT_UInt32)( a & 0xFFFFU ); + /* divide the result by 2^14 with rounding */ + l = lo + 0x2000U + (FT_UInt32)( hi >> 31 ); /* rounding phase */ + hi += ( l < lo ); - lo = al * b; - mid = ah * b; - hi = mid >> 16; - mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */ - lo += mid; - if ( lo < mid ) - hi += 1; - - mid = ( lo >> 14 ) | ( hi << 18 ); - - return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid; + return (FT_F26Dot6)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); } #endif /* !TT_MulFix14 */ -#if defined( __GNUC__ ) && \ - ( defined( __i386__ ) || \ - defined( __x86_64__ ) || \ - defined( __arm__ ) ) - -#define TT_DotFix14 TT_DotFix14_long_long - -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic push -#endif -#pragma GCC diagnostic ignored "-Wlong-long" - - static __attribute__(( pure )) FT_Int32 - TT_DotFix14_long_long( FT_Int32 ax, - FT_Int32 ay, - FT_Int bx, - FT_Int by ) - { - /* Temporarily disable the warning that C90 doesn't support */ - /* `long long'. */ - - long long temp1 = (long long)ax * bx; - long long temp2 = (long long)ay * by; - - - temp1 += temp2; - temp2 = temp1 >> 63; - temp1 += 0x2000 + temp2; - - return (FT_Int32)( temp1 >> 14 ); - - } - -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic pop -#endif - -#endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */ - - -#ifndef TT_DotFix14 +#ifdef FT_INT64 /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */ - static FT_Int32 - TT_DotFix14( FT_Int32 ax, - FT_Int32 ay, - FT_Int bx, - FT_Int by ) + static inline FT_F26Dot6 + TT_DotFix14( FT_F26Dot6 ax, + FT_F26Dot6 ay, + FT_F2Dot14 bx, + FT_F2Dot14 by ) { - FT_Int32 m, s, hi1, hi2, hi; + FT_Int64 c = ADD_INT64( MUL_INT64( ax, bx ), MUL_INT64( ay, by ) ); + + + c = ADD_INT64( c, 0x2000 + ( c >> 63 ) ); /* rounding phase */ + + return (FT_F26Dot6)( c >> 14 ); + } + +#else + + static inline FT_F26Dot6 + TT_DotFix14( FT_F26Dot6 ax, + FT_F26Dot6 ay, + FT_F2Dot14 bx, + FT_F2Dot14 by ) + { + FT_Int32 m, hi1, hi2, hi; FT_UInt32 l, lo1, lo2, lo; - /* compute ax*bx as 64-bit value */ + /* compute ax*bx as 64-bit (hi_lo) value */ l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx ); m = ( ax >> 16 ) * bx; @@ -1366,18 +1233,13 @@ hi = hi1 + hi2 + ( lo < lo1 ); /* divide the result by 2^14 with rounding */ - s = hi >> 31; - l = lo + (FT_UInt32)s; - hi += s + ( l < lo ); - lo = l; - - l = lo + 0x2000U; + l = lo + 0x2000U + (FT_UInt32)( hi >> 31 ); /* rounding phase */ hi += ( l < lo ); - return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); + return (FT_F26Dot6)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); } -#endif /* TT_DotFix14 */ +#endif /* !FT_INT64 */ /************************************************************************** @@ -1531,31 +1393,6 @@ } - /************************************************************************** - * - * @Function: - * GetShortIns - * - * @Description: - * Returns a short integer taken from the instruction stream at - * address IP. - * - * @Return: - * Short read at code[IP]. - * - * @Note: - * This one could become a macro. - */ - static FT_Short - GetShortIns( TT_ExecContext exc ) - { - /* Reading a byte stream so there is no endianness (DaveP) */ - exc->IP += 2; - return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) + - exc->code[exc->IP - 1] ); - } - - /************************************************************************** * * @Function: @@ -1609,6 +1446,7 @@ exc->code = range->base; exc->codeSize = range->size; exc->IP = aIP; + exc->length = 0; exc->curRange = aRange; return SUCCESS; @@ -1671,48 +1509,33 @@ FT_UShort point, FT_F26Dot6 distance ) { - FT_F26Dot6 v; + FT_Fixed v; - v = exc->GS.freeVector.x; - + v = exc->moveVector.x; if ( v != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* Exception to the post-IUP curfew: Allow the x component of */ /* diagonal moves, but only post-IUP. DejaVu tries to adjust */ /* diagonal stems like on `Z' and `z' post-IUP. */ - if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) - zone->cur[point].x = ADD_LONG( zone->cur[point].x, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); - else + if ( !exc->backward_compatibility ) #endif - - if ( NO_SUBPIXEL_HINTING ) zone->cur[point].x = ADD_LONG( zone->cur[point].x, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; } - v = exc->GS.freeVector.y; - + v = exc->moveVector.y; if ( v != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) #endif zone->cur[point].y = ADD_LONG( zone->cur[point].y, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -1745,24 +1568,20 @@ FT_UShort point, FT_F26Dot6 distance ) { - FT_F26Dot6 v; + FT_Fixed v; - v = exc->GS.freeVector.x; + v = exc->moveVector.x; if ( v != 0 ) zone->org[point].x = ADD_LONG( zone->org[point].x, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); - v = exc->GS.freeVector.y; + v = exc->moveVector.y; if ( v != 0 ) zone->org[point].y = ADD_LONG( zone->org[point].y, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); } @@ -1784,12 +1603,8 @@ FT_F26Dot6 distance ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) - zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); - else + if ( !exc->backward_compatibility ) #endif - - if ( NO_SUBPIXEL_HINTING ) zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; @@ -1805,9 +1620,8 @@ FT_UNUSED( exc ); #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && exc->iupy_called ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) #endif zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance ); @@ -1860,8 +1674,8 @@ * distance :: * The distance (not) to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * The compensated distance. @@ -1869,10 +1683,10 @@ static FT_F26Dot6 Round_None( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; + FT_UNUSED( exc ); if ( distance >= 0 ) @@ -1903,8 +1717,8 @@ * distance :: * The distance to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * Rounded distance. @@ -1912,10 +1726,10 @@ static FT_F26Dot6 Round_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; + FT_UNUSED( exc ); if ( distance >= 0 ) @@ -1948,8 +1762,8 @@ * distance :: * The distance to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * Rounded distance. @@ -1957,10 +1771,10 @@ static FT_F26Dot6 Round_To_Half_Grid( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; + FT_UNUSED( exc ); if ( distance >= 0 ) @@ -1995,8 +1809,8 @@ * distance :: * The distance to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * Rounded distance. @@ -2004,10 +1818,10 @@ static FT_F26Dot6 Round_Down_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; + FT_UNUSED( exc ); if ( distance >= 0 ) @@ -2039,8 +1853,8 @@ * distance :: * The distance to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * Rounded distance. @@ -2048,10 +1862,10 @@ static FT_F26Dot6 Round_Up_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; + FT_UNUSED( exc ); if ( distance >= 0 ) @@ -2084,8 +1898,8 @@ * distance :: * The distance to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * Rounded distance. @@ -2093,10 +1907,10 @@ static FT_F26Dot6 Round_To_Double_Grid( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; + FT_UNUSED( exc ); if ( distance >= 0 ) @@ -2129,8 +1943,8 @@ * distance :: * The distance to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * Rounded distance. @@ -2144,9 +1958,8 @@ static FT_F26Dot6 Round_Super( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; @@ -2185,8 +1998,8 @@ * distance :: * The distance to round. * - * color :: - * The engine compensation color. + * compensation :: + * The engine compensation. * * @Return: * Rounded distance. @@ -2198,9 +2011,8 @@ static FT_F26Dot6 Round_Super_45( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ) + FT_F26Dot6 compensation ) { - FT_F26Dot6 compensation = exc->tt_metrics.compensations[color]; FT_F26Dot6 val; @@ -2227,59 +2039,6 @@ } - /************************************************************************** - * - * @Function: - * Compute_Round - * - * @Description: - * Sets the rounding mode. - * - * @Input: - * round_mode :: - * The rounding mode to be used. - */ - static void - Compute_Round( TT_ExecContext exc, - FT_Byte round_mode ) - { - switch ( round_mode ) - { - case TT_Round_Off: - exc->func_round = (TT_Round_Func)Round_None; - break; - - case TT_Round_To_Grid: - exc->func_round = (TT_Round_Func)Round_To_Grid; - break; - - case TT_Round_Up_To_Grid: - exc->func_round = (TT_Round_Func)Round_Up_To_Grid; - break; - - case TT_Round_Down_To_Grid: - exc->func_round = (TT_Round_Func)Round_Down_To_Grid; - break; - - case TT_Round_To_Half_Grid: - exc->func_round = (TT_Round_Func)Round_To_Half_Grid; - break; - - case TT_Round_To_Double_Grid: - exc->func_round = (TT_Round_Func)Round_To_Double_Grid; - break; - - case TT_Round_Super: - exc->func_round = (TT_Round_Func)Round_Super; - break; - - case TT_Round_Super_45: - exc->func_round = (TT_Round_Func)Round_Super_45; - break; - } - } - - /************************************************************************** * * @Function: @@ -2481,14 +2240,45 @@ static void Compute_Funcs( TT_ExecContext exc ) { - if ( exc->GS.freeVector.x == 0x4000 ) - exc->F_dot_P = exc->GS.projVector.x; - else if ( exc->GS.freeVector.y == 0x4000 ) - exc->F_dot_P = exc->GS.projVector.y; + FT_Long F_dot_P = + ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x + + (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y + + 0x2000L ) >> 14; + + + if ( F_dot_P >= 0x3FFEL ) + { + /* commonly collinear */ + exc->moveVector.x = exc->GS.freeVector.x * 4; + exc->moveVector.y = exc->GS.freeVector.y * 4; + } + else if ( -0x400L < F_dot_P && F_dot_P < 0x400L ) + { + /* prohibitively orthogonal */ + exc->moveVector.x = 0; + exc->moveVector.y = 0; + } else - exc->F_dot_P = - ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x + - (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14; + { + exc->moveVector.x = exc->GS.freeVector.x * 0x10000L / F_dot_P; + exc->moveVector.y = exc->GS.freeVector.y * 0x10000L / F_dot_P; + } + + if ( F_dot_P >= 0x3FFEL && exc->GS.freeVector.x == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_X; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; + } + else if ( F_dot_P >= 0x3FFEL && exc->GS.freeVector.y == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_Y; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y; + } + else + { + exc->func_move = (TT_Move_Func)Direct_Move; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig; + } if ( exc->GS.projVector.x == 0x4000 ) exc->func_project = (TT_Project_Func)Project_x; @@ -2504,29 +2294,6 @@ else exc->func_dualproj = (TT_Project_Func)Dual_Project; - exc->func_move = (TT_Move_Func)Direct_Move; - exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig; - - if ( exc->F_dot_P == 0x4000L ) - { - if ( exc->GS.freeVector.x == 0x4000 ) - { - exc->func_move = (TT_Move_Func)Direct_Move_X; - exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; - } - else if ( exc->GS.freeVector.y == 0x4000 ) - { - exc->func_move = (TT_Move_Func)Direct_Move_Y; - exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y; - } - } - - /* at small sizes, F_dot_P can become too small, resulting */ - /* in overflows and `spikes' in a number of glyphs like `w'. */ - - if ( FT_ABS( exc->F_dot_P ) < 0x400L ) - exc->F_dot_P = 0x4000L; - /* Disable cached aspect ratio */ exc->tt_metrics.ratio = 0; } @@ -2799,7 +2566,7 @@ Ins_ODD( TT_ExecContext exc, FT_Long* args ) { - args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 64 ); + args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 64 ) == 64 ); } @@ -2813,7 +2580,7 @@ Ins_EVEN( TT_ExecContext exc, FT_Long* args ) { - args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 0 ); + args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 64 ) == 0 ); } @@ -3020,7 +2787,7 @@ FT_MEM_QRENEW_ARRAY( exc->glyfStorage, exc->glyfStoreSize, exc->storeSize ); - exc->error = error; + exc->error = error; if ( error ) return; @@ -3143,7 +2910,8 @@ Ins_ROUND( TT_ExecContext exc, FT_Long* args ) { - args[0] = exc->func_round( exc, args[0], exc->opcode & 3 ); + args[0] = exc->func_round( exc, args[0], + exc->GS.compensation[exc->opcode & 3] ); } @@ -3157,7 +2925,8 @@ Ins_NROUND( TT_ExecContext exc, FT_Long* args ) { - args[0] = Round_None( exc, args[0], exc->opcode & 3 ); + args[0] = Round_None( exc, args[0], + exc->GS.compensation[exc->opcode & 3] ); } @@ -3211,13 +2980,11 @@ } else { - K = exc->stack[exc->args - L]; + K = args[-L]; - FT_ARRAY_MOVE( &exc->stack[exc->args - L ], - &exc->stack[exc->args - L + 1], - ( L - 1 ) ); + FT_ARRAY_MOVE( args - L, args - L + 1, L - 1 ); - exc->stack[exc->args - 1] = K; + args[-1] = K; } } @@ -3244,7 +3011,7 @@ args[0] = 0; } else - args[0] = exc->stack[exc->args - L]; + args[0] = args[-L]; } @@ -3314,8 +3081,7 @@ exc->length = 2 - exc->length * exc->code[exc->IP + 1]; } - if ( exc->IP + exc->length <= exc->codeSize ) - return SUCCESS; + return SUCCESS; } Fail_Overflow: @@ -3363,6 +3129,9 @@ nIfs--; Out = FT_BOOL( nIfs == 0 ); break; + + default: + break; } } while ( Out == 0 ); } @@ -3396,6 +3165,9 @@ case 0x59: /* EIF */ nIfs--; break; + + default: + break; } } while ( nIfs != 0 ); } @@ -3439,7 +3211,7 @@ return; } - exc->step_ins = FALSE; + exc->length = 0; if ( args[0] < 0 ) { @@ -3540,10 +3312,10 @@ return; } - rec->range = exc->curRange; - rec->opc = (FT_UInt16)n; - rec->start = exc->IP + 1; - rec->active = TRUE; + rec->range = exc->curRange; + rec->opc = (FT_UInt16)n; + rec->start = exc->IP + 1; + rec->active = TRUE; if ( n > exc->maxFunc ) exc->maxFunc = (FT_UInt16)n; @@ -3555,14 +3327,17 @@ { switch ( exc->opcode ) { - case 0x89: /* IDEF */ - case 0x2C: /* FDEF */ + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ exc->error = FT_THROW( Nested_DEFS ); return; case 0x2D: /* ENDF */ rec->end = exc->IP; return; + + default: + break; } } } @@ -3592,12 +3367,11 @@ pRec->Cur_Count--; - exc->step_ins = FALSE; - if ( pRec->Cur_Count > 0 ) { exc->callTop++; - exc->IP = pRec->Def->start; + exc->IP = pRec->Def->start; + exc->length = 0; } else /* Loop through the current function */ @@ -3685,8 +3459,6 @@ Ins_Goto_CodeRange( exc, def->range, def->start ); - exc->step_ins = FALSE; - return; Fail: @@ -3764,8 +3536,6 @@ Ins_Goto_CodeRange( exc, def->range, def->start ); - exc->step_ins = FALSE; - exc->loopcall_counter += (FT_ULong)args[0]; if ( exc->loopcall_counter > exc->loopcall_counter_max ) exc->error = FT_THROW( Execution_Too_Long ); @@ -3845,9 +3615,13 @@ case 0x2C: /* FDEF */ exc->error = FT_THROW( Nested_DEFS ); return; + case 0x2D: /* ENDF */ def->end = exc->IP; return; + + default: + break; } } } @@ -3870,10 +3644,23 @@ Ins_NPUSHB( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)exc->code[exc->IP + 1]; + if ( ++IP >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } + + L = exc->code[IP]; + + if ( IP + L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -3881,10 +3668,11 @@ return; } - for ( K = 1; K <= L; K++ ) - args[K - 1] = exc->code[exc->IP + K + 1]; + for ( K = 0; K < L; K++ ) + args[K] = exc->code[++IP]; exc->new_top += L; + exc->IP = IP; } @@ -3898,10 +3686,23 @@ Ins_NPUSHW( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)exc->code[exc->IP + 1]; + if ( ++IP >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } + + L = exc->code[IP]; + + if ( IP + 2 * L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -3909,13 +3710,12 @@ return; } - exc->IP += 2; + /* note casting for sign-extension */ + for ( K = 0; K < L; K++, IP += 2 ) + args[K] = (FT_Short)( exc->code[IP + 1] << 8 ) | exc->code[IP + 2]; - for ( K = 0; K < L; K++ ) - args[K] = GetShortIns( exc ); - - exc->step_ins = FALSE; exc->new_top += L; + exc->IP = IP; } @@ -3929,10 +3729,17 @@ Ins_PUSHB( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)( exc->opcode - 0xB0 + 1 ); + L = exc->opcode - 0xB0 + 1; + + if ( IP + L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -3940,8 +3747,10 @@ return; } - for ( K = 1; K <= L; K++ ) - args[K - 1] = exc->code[exc->IP + K]; + for ( K = 0; K < L; K++ ) + args[K] = exc->code[++IP]; + + exc->IP = IP; } @@ -3955,10 +3764,17 @@ Ins_PUSHW( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)( exc->opcode - 0xB8 + 1 ); + L = exc->opcode - 0xB8 + 1; + + if ( IP + 2 * L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -3966,12 +3782,11 @@ return; } - exc->IP++; + /* note casting for sign-extension */ + for ( K = 0; K < L; K++, IP += 2 ) + args[K] = (FT_Short)( exc->code[IP + 1] << 8 ) | exc->code[IP + 2]; - for ( K = 0; K < L; K++ ) - args[K] = GetShortIns( exc ); - - exc->step_ins = FALSE; + exc->IP = IP; } @@ -4142,15 +3957,12 @@ Ins_SPVFS( TT_ExecContext exc, FT_Long* args ) { - FT_Short S; FT_Long X, Y; /* Only use low 16bits, then sign extend */ - S = (FT_Short)args[1]; - Y = (FT_Long)S; - S = (FT_Short)args[0]; - X = (FT_Long)S; + Y = (FT_Short)args[1]; + X = (FT_Short)args[0]; Normalize( X, Y, &exc->GS.projVector ); @@ -4169,15 +3981,12 @@ Ins_SFVFS( TT_ExecContext exc, FT_Long* args ) { - FT_Short S; FT_Long X, Y; /* Only use low 16bits, then sign extend */ - S = (FT_Short)args[1]; - Y = (FT_Long)S; - S = (FT_Short)args[0]; - X = S; + Y = (FT_Short)args[1]; + X = (FT_Short)args[0]; Normalize( X, Y, &exc->GS.freeVector ); Compute_Funcs( exc ); @@ -4915,7 +4724,7 @@ /* compatibility hacks and lets them program points to the grid like */ /* it's 1996. They might sign a waiver for just one glyph, though. */ if ( SUBPIXEL_HINTING_MINIMAL ) - exc->backward_compatibility = !FT_BOOL( L == 4 ); + exc->backward_compatibility = ( L & 4 ) ^ 4; #endif } else if ( exc->pedantic_hinting ) @@ -4999,32 +4808,31 @@ * Stack: uint32... --> */ static void - Ins_FLIPPT( TT_ExecContext exc ) + Ins_FLIPPT( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_UShort point; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* See `ttinterp.h' for details on backward compatibility mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) - goto Fail; -#endif - - if ( exc->top < exc->GS.loop ) + if ( exc->new_top < loop ) { if ( exc->pedantic_hinting ) exc->error = FT_THROW( Too_Few_Arguments ); goto Fail; } - while ( exc->GS.loop > 0 ) - { - exc->args--; + exc->new_top -= loop; - point = (FT_UShort)exc->stack[exc->args]; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility == 0x7 ) + goto Fail; +#endif + + while ( loop-- ) + { + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->pts.n_points ) ) { @@ -5036,13 +4844,10 @@ } else exc->pts.tags[point] ^= FT_CURVE_TAG_ON; - - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -5061,10 +4866,7 @@ #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* See `ttinterp.h' for details on backward compatibility mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) + if ( exc->backward_compatibility == 0x7 ) return; #endif @@ -5099,10 +4901,7 @@ #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* See `ttinterp.h' for details on backward compatibility mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) + if ( exc->backward_compatibility == 0x7 ) return; #endif @@ -5158,8 +4957,8 @@ d = PROJECT( zp.cur + p, zp.org + p ); - *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P ); - *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P ); + *x = FT_MulFix( d, exc->moveVector.x ); + *y = FT_MulFix( d, exc->moveVector.y ); return SUCCESS; } @@ -5176,8 +4975,8 @@ if ( exc->GS.freeVector.x != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( !exc->backward_compatibility ) #endif exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx ); @@ -5188,10 +4987,8 @@ if ( exc->GS.freeVector.y != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) #endif exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy ); @@ -5208,8 +5005,10 @@ * Stack: uint32... --> */ static void - Ins_SHP( TT_ExecContext exc ) + Ins_SHP( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; TT_GlyphZoneRec zp; FT_UShort refp; @@ -5217,20 +5016,21 @@ FT_UShort point; - if ( exc->top < exc->GS.loop ) + if ( exc->new_top < loop ) { if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); + exc->error = FT_THROW( Too_Few_Arguments ); goto Fail; } + exc->new_top -= loop; + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) return; - while ( exc->GS.loop > 0 ) + while ( loop-- ) { - exc->args--; - point = (FT_UShort)exc->stack[exc->args]; + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) { @@ -5242,13 +5042,10 @@ } else Move_Zp2_Point( exc, point, dx, dy, TRUE ); - - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -5364,6 +5161,7 @@ Ins_SHPIX( TT_ExecContext exc, FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_F26Dot6 dx, dy; FT_UShort point; #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL @@ -5373,22 +5171,21 @@ #endif - - if ( exc->top < exc->GS.loop + 1 ) + if ( exc->new_top < loop ) { if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); + exc->error = FT_THROW( Too_Few_Arguments ); goto Fail; } + exc->new_top -= loop; + dx = TT_MulFix14( args[0], exc->GS.freeVector.x ); dy = TT_MulFix14( args[0], exc->GS.freeVector.y ); - while ( exc->GS.loop > 0 ) + while ( loop-- ) { - exc->args--; - - point = (FT_UShort)exc->stack[exc->args]; + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) { @@ -5400,8 +5197,7 @@ } else #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) + if ( exc->backward_compatibility ) { /* Special case: allow SHPIX to move points in the twilight zone. */ /* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various */ @@ -5409,7 +5205,7 @@ /* that would glitch severely after calling ALIGNRP after a */ /* blocked SHPIX. */ if ( in_twilight || - ( !( exc->iupx_called && exc->iupy_called ) && + ( exc->backward_compatibility != 0x7 && ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) ) Move_Zp2_Point( exc, point, 0, dy, TRUE ); @@ -5417,13 +5213,10 @@ else #endif Move_Zp2_Point( exc, point, dx, dy, TRUE ); - - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -5502,7 +5295,7 @@ if ( ( exc->opcode & 1 ) != 0 ) { cur_dist = FAST_PROJECT( &exc->zp0.cur[point] ); - distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist ); + distance = SUB_LONG( exc->func_round( exc, cur_dist, 0 ), cur_dist ); } else distance = 0; @@ -5566,7 +5359,7 @@ if ( exc->GS.gep0 == 0 ) /* If in twilight zone */ { exc->zp0.org[point].x = TT_MulFix14( distance, - exc->GS.freeVector.x ); + exc->GS.freeVector.x ); exc->zp0.org[point].y = TT_MulFix14( distance, exc->GS.freeVector.y ); exc->zp0.cur[point] = exc->zp0.org[point]; @@ -5587,7 +5380,7 @@ if ( delta > control_value_cutin ) distance = org_dist; - distance = exc->func_round( exc, distance, 3 ); + distance = exc->func_round( exc, distance, 0 ); } exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) ); @@ -5609,7 +5402,7 @@ FT_Long* args ) { FT_UShort point = 0; - FT_F26Dot6 org_dist, distance; + FT_F26Dot6 org_dist, distance, compensation; point = (FT_UShort)args[0]; @@ -5678,12 +5471,12 @@ /* round flag */ + compensation = exc->GS.compensation[exc->opcode & 3]; + if ( ( exc->opcode & 4 ) != 0 ) - { - distance = exc->func_round( exc, org_dist, exc->opcode & 3 ); - } + distance = exc->func_round( exc, org_dist, compensation ); else - distance = Round_None( exc, org_dist, exc->opcode & 3 ); + distance = Round_None( exc, org_dist, compensation ); /* minimum distance flag */ @@ -5735,7 +5528,8 @@ FT_F26Dot6 cvt_dist, distance, cur_dist, - org_dist; + org_dist, + compensation; FT_F26Dot6 delta; @@ -5801,6 +5595,8 @@ /* control value cut-in and round */ + compensation = exc->GS.compensation[exc->opcode & 3]; + if ( ( exc->opcode & 4 ) != 0 ) { /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ @@ -5831,16 +5627,16 @@ cvt_dist = org_dist; } - distance = exc->func_round( exc, cvt_dist, exc->opcode & 3 ); + distance = exc->func_round( exc, cvt_dist, compensation ); } else - distance = Round_None( exc, cvt_dist, exc->opcode & 3 ); + distance = Round_None( exc, cvt_dist, compensation ); /* minimum distance test */ if ( ( exc->opcode & 8 ) != 0 ) { - FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; + FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; if ( org_dist >= 0 ) @@ -5862,11 +5658,10 @@ Fail: exc->GS.rp1 = exc->GS.rp0; + exc->GS.rp2 = point; if ( ( exc->opcode & 16 ) != 0 ) exc->GS.rp0 = point; - - exc->GS.rp2 = point; } @@ -5877,25 +5672,33 @@ * Stack: uint32 uint32... --> */ static void - Ins_ALIGNRP( TT_ExecContext exc ) + Ins_ALIGNRP( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_UShort point; FT_F26Dot6 distance; - if ( exc->top < exc->GS.loop || - BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + if ( exc->new_top < loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + goto Fail; + } + + exc->new_top -= loop; + + if ( BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) { if ( exc->pedantic_hinting ) exc->error = FT_THROW( Invalid_Reference ); goto Fail; } - while ( exc->GS.loop > 0 ) + while ( loop-- ) { - exc->args--; - - point = (FT_UShort)exc->stack[exc->args]; + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->zp1.n_points ) ) { @@ -5912,13 +5715,10 @@ exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) ); } - - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -6060,15 +5860,26 @@ /* SOMETIMES, DUMBER CODE IS BETTER CODE */ static void - Ins_IP( TT_ExecContext exc ) + Ins_IP( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_F26Dot6 old_range, cur_range; FT_Vector* orus_base; FT_Vector* cur_base; FT_Int twilight; - if ( exc->top < exc->GS.loop ) + if ( exc->new_top < loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + goto Fail; + } + + exc->new_top -= loop; + + if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ) { if ( exc->pedantic_hinting ) exc->error = FT_THROW( Invalid_Reference ); @@ -6084,13 +5895,6 @@ exc->GS.gep1 == 0 || exc->GS.gep2 == 0 ); - if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); - goto Fail; - } - if ( twilight ) orus_base = &exc->zp0.org[exc->GS.rp1]; else @@ -6102,8 +5906,7 @@ /* fonts out there (e.g. [aeu]grave in monotype.ttf) */ /* calling IP[] with bad values of rp[12]. */ /* Do something sane when this odd thing happens. */ - if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) || - BOUNDS( exc->GS.rp2, exc->zp1.n_points ) ) + if ( BOUNDS( exc->GS.rp2, exc->zp1.n_points ) ) { old_range = 0; cur_range = 0; @@ -6132,9 +5935,9 @@ cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base ); } - for ( ; exc->GS.loop > 0; exc->GS.loop-- ) + while ( loop-- ) { - FT_UInt point = (FT_UInt)exc->stack[--exc->args]; + FT_UInt point = (FT_UInt)*(--args); FT_F26Dot6 org_dist, cur_dist, new_dist; @@ -6206,7 +6009,6 @@ Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -6405,17 +6207,10 @@ /* See `ttinterp.h' for details on backward compatibility mode. */ /* Allow IUP until it has been called on both axes. Immediately */ /* return on subsequent ones. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) - { - if ( exc->iupx_called && exc->iupy_called ) - return; - - if ( exc->opcode & 1 ) - exc->iupx_called = TRUE; - else - exc->iupy_called = TRUE; - } + if ( exc->backward_compatibility == 0x7 ) + return; + else if ( exc->backward_compatibility ) + exc->backward_compatibility |= 1 << ( exc->opcode & 1 ); #endif /* ignore empty outlines */ @@ -6507,30 +6302,50 @@ Ins_DELTAP( TT_ExecContext exc, FT_Long* args ) { - FT_ULong nump, k; + FT_Long nump; FT_UShort A; - FT_ULong C, P; - FT_Long B; + FT_Long B, P, F; - P = (FT_ULong)exc->func_cur_ppem( exc ); - nump = (FT_ULong)args[0]; /* some points theoretically may occur more - than once, thus UShort isn't enough */ + nump = args[0]; /* signed value for convenience */ - for ( k = 1; k <= nump; k++ ) + if ( nump < 0 || nump > exc->new_top / 2 ) { - if ( exc->args < 2 ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Too_Few_Arguments ); - exc->args = 0; - goto Fail; - } + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); - exc->args -= 2; + nump = exc->new_top / 2; + } - A = (FT_UShort)exc->stack[exc->args + 1]; - B = exc->stack[exc->args]; + exc->new_top -= 2 * nump; + + P = exc->func_cur_ppem( exc ) - exc->GS.delta_base; + + switch ( exc->opcode ) + { + case 0x5D: + break; + + case 0x71: + P -= 16; + break; + + case 0x72: + P -= 32; + break; + } + + /* check applicable range of adjusted ppem */ + if ( P & ~0xF ) /* P < 0 || P > 15 */ + return; + + P <<= 4; + F = 1L << ( 6 - exc->GS.delta_shift ); + + while ( nump-- ) + { + A = (FT_UShort)*(--args); + B = *(--args); /* XXX: Because some popular fonts contain some invalid DeltaP */ /* instructions, we simply ignore them when the stacked */ @@ -6538,41 +6353,28 @@ /* error. As a delta instruction doesn't change a glyph */ /* in great ways, this shouldn't be a problem. */ - if ( !BOUNDS( A, exc->zp0.n_points ) ) + if ( BOUNDS( A, exc->zp0.n_points ) ) { - C = ( (FT_ULong)B & 0xF0 ) >> 4; - - switch ( exc->opcode ) + if ( exc->pedantic_hinting ) { - case 0x5D: - break; - - case 0x71: - C += 16; - break; - - case 0x72: - C += 32; - break; + exc->error = FT_THROW( Invalid_Reference ); + return; } - - C += exc->GS.delta_base; - - if ( P == C ) + } + else + { + if ( ( B & 0xF0 ) == P ) { - B = ( (FT_ULong)B & 0xF ) - 8; + B = ( B & 0xF ) - 8; if ( B >= 0 ) B++; - B *= 1L << ( 6 - exc->GS.delta_shift ); - + B *= F; #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* See `ttinterp.h' for details on backward compatibility */ - /* mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility ) { - if ( !( exc->iupx_called && exc->iupy_called ) && + if ( exc->backward_compatibility != 0x7 && ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) ) exc->func_move( exc, &exc->zp0, A, B ); @@ -6582,13 +6384,7 @@ exc->func_move( exc, &exc->zp0, A, B ); } } - else - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); } - - Fail: - exc->new_top = exc->args; } @@ -6602,28 +6398,50 @@ Ins_DELTAC( TT_ExecContext exc, FT_Long* args ) { - FT_ULong nump, k; - FT_ULong A, C, P; - FT_Long B; + FT_Long nump; + FT_ULong A; + FT_Long B, P, F; - P = (FT_ULong)exc->func_cur_ppem( exc ); - nump = (FT_ULong)args[0]; + nump = args[0]; /* signed value for convenience */ - for ( k = 1; k <= nump; k++ ) + if ( nump < 0 || nump > exc->new_top / 2 ) { - if ( exc->args < 2 ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Too_Few_Arguments ); - exc->args = 0; - goto Fail; - } + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); - exc->args -= 2; + nump = exc->new_top / 2; + } - A = (FT_ULong)exc->stack[exc->args + 1]; - B = exc->stack[exc->args]; + exc->new_top -= 2 * nump; + + P = exc->func_cur_ppem( exc ) - exc->GS.delta_base; + + switch ( exc->opcode ) + { + case 0x73: + break; + + case 0x74: + P -= 16; + break; + + case 0x75: + P -= 32; + break; + } + + /* check applicable range of adjusted ppem */ + if ( P & ~0xF ) /* P < 0 || P > 15 */ + return; + + P <<= 4; + F = 1L << ( 6 - exc->GS.delta_shift ); + + while ( nump-- ) + { + A = (FT_ULong)*(--args); + B = *(--args); if ( BOUNDSL( A, exc->cvtSize ) ) { @@ -6635,38 +6453,17 @@ } else { - C = ( (FT_ULong)B & 0xF0 ) >> 4; - - switch ( exc->opcode ) + if ( ( B & 0xF0 ) == P ) { - case 0x73: - break; - - case 0x74: - C += 16; - break; - - case 0x75: - C += 32; - break; - } - - C += exc->GS.delta_base; - - if ( P == C ) - { - B = ( (FT_ULong)B & 0xF ) - 8; + B = ( B & 0xF ) - 8; if ( B >= 0 ) B++; - B *= 1L << ( 6 - exc->GS.delta_shift ); + B *= F; exc->func_move_cvt( exc, A, B ); } } } - - Fail: - exc->new_top = exc->args; } @@ -6736,7 +6533,7 @@ /* Otherwise, instructions may behave weirdly and rendering results */ /* may differ between v35 and v40 mode, e.g., in `Times New Roman */ /* Bold Italic'. */ - if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean ) + if ( SUBPIXEL_HINTING_MINIMAL && exc->mode != FT_RENDER_MODE_MONO ) { /********************************* * HINTING FOR SUBPIXEL @@ -6753,7 +6550,7 @@ * Selector Bit: 8 * Return Bit(s): 15 */ - if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean ) + if ( ( args[0] & 256 ) != 0 && exc->mode == FT_RENDER_MODE_LCD_V ) K |= 1 << 15; /********************************* @@ -6774,7 +6571,7 @@ * The only smoothing method FreeType supports unless someone sets * FT_LOAD_TARGET_MONO. */ - if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean ) + if ( ( args[0] & 2048 ) != 0 && exc->mode != FT_RENDER_MODE_MONO ) K |= 1 << 18; /********************************* @@ -6786,7 +6583,10 @@ * Grayscale rendering is what FreeType does anyway unless someone * sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */ - if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype ) + if ( ( args[0] & 4096 ) != 0 && + exc->mode != FT_RENDER_MODE_MONO && + exc->mode != FT_RENDER_MODE_LCD && + exc->mode != FT_RENDER_MODE_LCD_V ) K |= 1 << 19; } #endif @@ -6833,6 +6633,8 @@ for ( i = 0; i < num_axes; i++ ) args[i] = 0; } + + exc->new_top += num_axes; } @@ -6883,7 +6685,6 @@ Ins_Goto_CodeRange( exc, def->range, def->start ); - exc->step_ins = FALSE; return; } } @@ -6928,96 +6729,22 @@ TT_RunIns( void* exec ) { TT_ExecContext exc = (TT_ExecContext)exec; + FT_ULong ins_counter = 0; - FT_ULong ins_counter = 0; /* executed instructions counter */ - FT_ULong num_twilight_points; - FT_UShort i; - - - /* We restrict the number of twilight points to a reasonable, */ - /* heuristic value to avoid slow execution of malformed bytecode. */ - num_twilight_points = FT_MAX( 30, - 2 * ( exc->pts.n_points + exc->cvtSize ) ); - if ( exc->twilight.n_points > num_twilight_points ) - { - if ( num_twilight_points > 0xFFFFU ) - num_twilight_points = 0xFFFFU; - - FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" )); - FT_TRACE5(( " from %d to the more reasonable value %ld\n", - exc->twilight.n_points, - num_twilight_points )); - exc->twilight.n_points = (FT_UShort)num_twilight_points; - } - - /* Set up loop detectors. We restrict the number of LOOPCALL loops */ - /* and the number of JMPR, JROT, and JROF calls with a negative */ - /* argument to values that depend on various parameters like the */ - /* size of the CVT table or the number of points in the current */ - /* glyph (if applicable). */ - /* */ - /* The idea is that in real-world bytecode you either iterate over */ - /* all CVT entries (in the `prep' table), or over all points (or */ - /* contours, in the `glyf' table) of a glyph, and such iterations */ - /* don't happen very often. */ - exc->loopcall_counter = 0; - exc->neg_jump_counter = 0; - - /* The maximum values are heuristic. */ - if ( exc->pts.n_points ) - exc->loopcall_counter_max = FT_MAX( 50, - 10 * exc->pts.n_points ) + - FT_MAX( 50, - exc->cvtSize / 10 ); - else - exc->loopcall_counter_max = 300 + 22 * exc->cvtSize; - - /* as a protection against an unreasonable number of CVT entries */ - /* we assume at most 100 control values per glyph for the counter */ - if ( exc->loopcall_counter_max > - 100 * (FT_ULong)exc->face->root.num_glyphs ) - exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs; - - FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL" - " to %ld\n", exc->loopcall_counter_max )); - - exc->neg_jump_counter_max = exc->loopcall_counter_max; - FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps" - " to %ld\n", exc->neg_jump_counter_max )); - - /* set PPEM and CVT functions */ - exc->tt_metrics.ratio = 0; - if ( exc->metrics.x_ppem != exc->metrics.y_ppem ) - { - /* non-square pixels, use the stretched routines */ - exc->func_cur_ppem = Current_Ppem_Stretched; - exc->func_read_cvt = Read_CVT_Stretched; - exc->func_write_cvt = Write_CVT_Stretched; - exc->func_move_cvt = Move_CVT_Stretched; - } - else - { - /* square pixels, use normal routines */ - exc->func_cur_ppem = Current_Ppem; - exc->func_read_cvt = Read_CVT; - exc->func_write_cvt = Write_CVT; - exc->func_move_cvt = Move_CVT; - } - - exc->iniRange = exc->curRange; - - Compute_Funcs( exc ); - Compute_Round( exc, (FT_Byte)exc->GS.round_state ); - - /* These flags cancel execution of some opcodes after IUP is called */ -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - exc->iupx_called = FALSE; - exc->iupy_called = FALSE; -#endif do { + /* increment instruction counter and check if we didn't */ + /* run this program for too long (e.g. infinite loops). */ + if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) + { + exc->error = FT_THROW( Execution_Too_Long ); + goto LErrorLabel_; + } + + exc->error = FT_Err_Ok; exc->opcode = exc->code[exc->IP]; + exc->length = 1; #ifdef FT_DEBUG_LEVEL_TRACE if ( ft_trace_levels[trace_ttinterp] >= 6 ) @@ -7041,17 +6768,6 @@ } #endif /* FT_DEBUG_LEVEL_TRACE */ - if ( ( exc->length = opcode_length[exc->opcode] ) < 0 ) - { - if ( exc->IP + 1 >= exc->codeSize ) - goto LErrorCodeOverflow_; - - exc->length = 2 - exc->length * exc->code[exc->IP + 1]; - } - - if ( exc->IP + exc->length > exc->codeSize ) - goto LErrorCodeOverflow_; - /* First, let's check for empty stack and overflow */ exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 ); @@ -7059,6 +6775,9 @@ /* One can also interpret it as the index of the last argument. */ if ( exc->args < 0 ) { + FT_UShort i; + + if ( exc->pedantic_hinting ) { exc->error = FT_THROW( Too_Few_Arguments ); @@ -7071,21 +6790,7 @@ exc->args = 0; } -#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( exc->opcode == 0x91 ) - { - /* this is very special: GETVARIATION returns */ - /* a variable number of arguments */ - - /* it is the job of the application to `activate' GX handling, */ - /* that is, calling any of the GX API functions on the current */ - /* font to select a variation instance */ - if ( exc->face->blend ) - exc->new_top = exc->args + exc->face->blend->num_axis; - } - else -#endif - exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 ); + exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 ); /* `new_top' is the new top of the stack, after the instruction's */ /* execution. `top' will be set to `new_top' after the `switch' */ @@ -7096,9 +6801,6 @@ goto LErrorLabel_; } - exc->step_ins = TRUE; - exc->error = FT_Err_Ok; - { FT_Long* args = exc->stack + exc->args; FT_Byte opcode = exc->opcode; @@ -7281,7 +6983,7 @@ case 0x32: /* SHP */ case 0x33: /* SHP */ - Ins_SHP( exc ); + Ins_SHP( exc, args ); break; case 0x34: /* SHC */ @@ -7299,7 +7001,7 @@ break; case 0x39: /* IP */ - Ins_IP( exc ); + Ins_IP( exc, args ); break; case 0x3A: /* MSIRP */ @@ -7308,7 +7010,7 @@ break; case 0x3C: /* AlignRP */ - Ins_ALIGNRP( exc ); + Ins_ALIGNRP( exc, args ); break; case 0x3D: /* RTDG */ @@ -7544,7 +7246,7 @@ break; case 0x80: /* FLIPPT */ - Ins_FLIPPT( exc ); + Ins_FLIPPT( exc, args ); break; case 0x81: /* FLIPRGON */ @@ -7642,13 +7344,13 @@ { switch ( exc->error ) { - /* looking for redefined instructions */ case FT_ERR( Invalid_Opcode ): { TT_DefRecord* def = exc->IDefs; TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); + /* looking for redefined instructions */ for ( ; def < limit; def++ ) { if ( def->active && exc->opcode == (FT_Byte)def->opc ) @@ -7678,37 +7380,15 @@ } } } - - exc->error = FT_THROW( Invalid_Opcode ); - goto LErrorLabel_; - -#if 0 - break; /* Unreachable code warning suppression. */ - /* Leave to remind in case a later change the editor */ - /* to consider break; */ -#endif + FALL_THROUGH; default: goto LErrorLabel_; - -#if 0 - break; -#endif } } exc->top = exc->new_top; - - if ( exc->step_ins ) - exc->IP += exc->length; - - /* increment instruction counter and check if we didn't */ - /* run this program for too long (e.g. infinite loops). */ - if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) - { - exc->error = FT_THROW( Execution_Too_Long ); - goto LErrorLabel_; - } + exc->IP += exc->length; LSuiteLabel_: if ( exc->IP >= exc->codeSize ) @@ -7724,15 +7404,12 @@ } while ( !exc->instruction_trap ); LNo_Error_: - FT_TRACE4(( " %ld instruction%s executed\n", + FT_TRACE4(( " %lu instruction%s executed\n", ins_counter, ins_counter == 1 ? "" : "s" )); return FT_Err_Ok; - LErrorCodeOverflow_: - exc->error = FT_THROW( Code_Overflow ); - LErrorLabel_: if ( exc->error && !exc->instruction_trap ) FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error )); @@ -7740,6 +7417,126 @@ return exc->error; } + + /************************************************************************** + * + * @Function: + * TT_Run_Context + * + * @Description: + * Executes one or more instructions in the execution context. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * @Return: + * TrueType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Run_Context( TT_ExecContext exec, + TT_Size size ) + { + FT_ULong num_twilight_points; + + + exec->zp0 = exec->pts; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + + /* We restrict the number of twilight points to a reasonable, */ + /* heuristic value to avoid slow execution of malformed bytecode. */ + /* The selected value is large enough to support fonts hinted */ + /* with `ttfautohint`, which uses twilight points to store */ + /* vertical coordinates of (auto-hinter) segments. */ + num_twilight_points = FT_MAX( 30, + 2 * ( exec->pts.n_points + exec->cvtSize ) ); + if ( exec->twilight.n_points > num_twilight_points ) + { + if ( num_twilight_points > 0xFFFFU ) + num_twilight_points = 0xFFFFU; + + FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" )); + FT_TRACE5(( " from %d to the more reasonable value %lu\n", + exec->twilight.n_points, + num_twilight_points )); + exec->twilight.n_points = (FT_UShort)num_twilight_points; + } + + /* Set up loop detectors. We restrict the number of LOOPCALL loops */ + /* and the number of JMPR, JROT, and JROF calls with a negative */ + /* argument to values that depend on various parameters like the */ + /* size of the CVT table or the number of points in the current */ + /* glyph (if applicable). */ + /* */ + /* The idea is that in real-world bytecode you either iterate over */ + /* all CVT entries (in the `prep' table), or over all points (or */ + /* contours, in the `glyf' table) of a glyph, and such iterations */ + /* don't happen very often. */ + exec->loopcall_counter = 0; + exec->neg_jump_counter = 0; + + /* The maximum values are heuristic. */ + if ( exec->pts.n_points ) + exec->loopcall_counter_max = FT_MAX( 50, + 10 * exec->pts.n_points ) + + FT_MAX( 50, + exec->cvtSize / 10 ); + else + exec->loopcall_counter_max = 300 + 22 * exec->cvtSize; + + /* as a protection against an unreasonable number of CVT entries */ + /* we assume at most 100 control values per glyph for the counter */ + if ( exec->loopcall_counter_max > + 100 * (FT_ULong)exec->face->root.num_glyphs ) + exec->loopcall_counter_max = 100 * (FT_ULong)exec->face->root.num_glyphs; + + FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL" + " to %lu\n", exec->loopcall_counter_max )); + + exec->neg_jump_counter_max = exec->loopcall_counter_max; + FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps" + " to %lu\n", exec->neg_jump_counter_max )); + + /* set PPEM and CVT functions */ + if ( exec->metrics.x_ppem != exec->metrics.y_ppem ) + { + /* non-square pixels, use the stretched routines */ + exec->func_cur_ppem = Current_Ppem_Stretched; + exec->func_read_cvt = Read_CVT_Stretched; + exec->func_write_cvt = Write_CVT_Stretched; + exec->func_move_cvt = Move_CVT_Stretched; + } + else + { + /* square pixels, use normal routines */ + exec->func_cur_ppem = Current_Ppem; + exec->func_read_cvt = Read_CVT; + exec->func_write_cvt = Write_CVT; + exec->func_move_cvt = Move_CVT; + } + + /* reset graphics state */ + exec->GS = size->GS; + exec->func_round = (TT_Round_Func)Round_To_Grid; + Compute_Funcs( exec ); + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Reset IUP tracking bits in the backward compatibility mode. */ + /* See `ttinterp.h' for details. */ + exec->backward_compatibility &= ~0x3; +#endif + + /* some glyphs leave something on the stack, */ + /* so we clean it before a new execution. */ + exec->top = 0; + exec->callTop = 0; + + exec->instruction_trap = FALSE; + + return exec->interpreter( exec ); + } + #else /* !TT_USE_BYTECODE_INTERPRETER */ /* ANSI C doesn't like empty source files */ diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h index 4f1a9bbc679..2e69d191890 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -39,6 +39,60 @@ FT_BEGIN_HEADER #define TT_Round_Super_45 7 + /************************************************************************** + * + * EXECUTION SUBTABLES + * + * These sub-tables relate to instruction execution. + * + */ + + +#define TT_MAX_CODE_RANGES 3 + + + /************************************************************************** + * + * There can only be 3 active code ranges at once: + * - the Font Program + * - the CVT Program + * - a glyph's instructions set + */ + typedef enum TT_CodeRange_Tag_ + { + tt_coderange_none = 0, + tt_coderange_font, + tt_coderange_cvt, + tt_coderange_glyph + + } TT_CodeRange_Tag; + + + typedef struct TT_CodeRange_ + { + FT_Byte* base; + FT_Long size; + + } TT_CodeRange; + + typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; + + + /************************************************************************** + * + * Defines a function/instruction definition record. + */ + typedef struct TT_DefRecord_ + { + FT_Int range; /* in which code range is it located? */ + FT_Long start; /* where does it start? */ + FT_Long end; /* where does it end? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ + + } TT_DefRecord, *TT_DefArray; + + /************************************************************************** * * Function types used by the interpreter, depending on various modes @@ -51,7 +105,7 @@ FT_BEGIN_HEADER typedef FT_F26Dot6 (*TT_Round_Func)( TT_ExecContext exc, FT_F26Dot6 distance, - FT_Int color ); + FT_F26Dot6 compensation ); /* Point displacement along the freedom vector routine */ typedef void @@ -111,12 +165,13 @@ FT_BEGIN_HEADER TT_Face face; /* ! */ TT_Size size; /* ! */ FT_Memory memory; + TT_Interpreter interpreter; /* instructions state */ FT_Error error; /* last execution error */ - FT_Long top; /* @ top of exec. stack */ + FT_Long top; /* @! top of exec. stack */ FT_Long stackSize; /* ! size of exec. stack */ FT_Long* stack; /* ! current exec. stack */ @@ -142,11 +197,9 @@ FT_BEGIN_HEADER FT_Long IP; /* current instruction pointer */ FT_Long codeSize; /* size of current range */ - FT_Byte opcode; /* current opcode */ - FT_Int length; /* length of current opcode */ + FT_Byte opcode; /* current opcode */ + FT_Int length; /* opcode length or increment */ - FT_Bool step_ins; /* true if the interpreter must */ - /* increment IP after ins. exec */ FT_ULong cvtSize; /* ! */ FT_Long* cvt; /* ! */ FT_ULong glyfCvtSize; @@ -166,9 +219,9 @@ FT_BEGIN_HEADER FT_UInt maxFunc; /* ! maximum function index */ FT_UInt maxIns; /* ! maximum instruction index */ - FT_Int callTop, /* @ top of call stack during execution */ - callSize; /* size of call stack */ - TT_CallStack callStack; /* call stack */ + FT_Int callTop, /* @! top of call stack during execution */ + callSize; /* size of call stack */ + TT_CallStack callStack; /* call stack */ FT_UShort maxPoints; /* capacity of this context's `pts' */ FT_Short maxContours; /* record, expressed in points and */ @@ -189,16 +242,14 @@ FT_BEGIN_HEADER FT_Bool instruction_trap; /* ! If `True', the interpreter */ /* exits after each instruction */ - TT_GraphicsState default_GS; /* graphics state resulting from */ - /* the prep program */ FT_Bool is_composite; /* true if the glyph is composite */ FT_Bool pedantic_hinting; /* true if pedantic interpretation */ /* latest interpreter additions */ - FT_Long F_dot_P; /* dot product of freedom and projection */ - /* vectors */ - TT_Round_Func func_round; /* current rounding function */ + TT_Round_Func func_round; /* current rounding function */ + + FT_Vector moveVector; /* "projected" freedom vector */ TT_Project_Func func_project, /* current projection function */ func_dualproj, /* current dual proj. function */ @@ -327,34 +378,13 @@ FT_BEGIN_HEADER * */ - /* Using v40 implies subpixel hinting, unless FT_RENDER_MODE_MONO has been - * requested. Used to detect interpreter */ - /* version switches. `_lean' to differentiate from the Infinality */ - /* `subpixel_hinting', which is managed differently. */ - FT_Bool subpixel_hinting_lean; + /* Activate backward compatibility (bit 2) and track IUP (bits 0-1). */ + /* If this is zero, it means that the interpreter is either in v35 */ + /* or in native ClearType mode. */ + FT_Int backward_compatibility; - /* Long side of a LCD subpixel is vertical (e.g., screen is rotated). */ - /* `_lean' to differentiate from the Infinality `vertical_lcd', which */ - /* is managed differently. */ - FT_Bool vertical_lcd_lean; + FT_Render_Mode mode; /* target render mode */ - /* Default to backward compatibility mode in v40 interpreter. If */ - /* this is false, it implies the interpreter is in v35 or in native */ - /* ClearType mode. */ - FT_Bool backward_compatibility; - - /* Useful for detecting and denying post-IUP trickery that is usually */ - /* used to fix pixel patterns (`superhinting'). */ - FT_Bool iupx_called; - FT_Bool iupy_called; - - /* ClearType hinting and grayscale rendering, as used by Universal */ - /* Windows Platform apps (Windows 8 and above). Like the standard */ - /* colorful ClearType mode, it utilizes a vastly increased virtual */ - /* resolution on the x axis. Different from bi-level hinting and */ - /* grayscale rendering, the old mode from Win9x days that roughly */ - /* adheres to the physical pixel grid on both axes. */ - FT_Bool grayscale_cleartype; #endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ /* We maintain two counters (in addition to the instruction counter) */ @@ -371,22 +401,15 @@ FT_BEGIN_HEADER extern const TT_GraphicsState tt_default_graphics_state; -#ifdef TT_USE_BYTECODE_INTERPRETER - FT_LOCAL( void ) - TT_Goto_CodeRange( TT_ExecContext exec, - FT_Int range, - FT_Long IP ); - FT_LOCAL( void ) TT_Set_CodeRange( TT_ExecContext exec, FT_Int range, - void* base, + FT_Byte* base, FT_Long length ); FT_LOCAL( void ) TT_Clear_CodeRange( TT_ExecContext exec, FT_Int range ); -#endif /* TT_USE_BYTECODE_INTERPRETER */ /************************************************************************** @@ -413,7 +436,6 @@ FT_BEGIN_HEADER TT_New_Context( TT_Driver driver ); -#ifdef TT_USE_BYTECODE_INTERPRETER FT_LOCAL( void ) TT_Done_Context( TT_ExecContext exec ); @@ -424,11 +446,11 @@ FT_BEGIN_HEADER FT_LOCAL( void ) TT_Save_Context( TT_ExecContext exec, - TT_Size ins ); + TT_Size size ); FT_LOCAL( FT_Error ) - TT_Run_Context( TT_ExecContext exec ); -#endif /* TT_USE_BYTECODE_INTERPRETER */ + TT_Run_Context( TT_ExecContext exec, + TT_Size size ); /************************************************************************** diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c index d0ac3181204..fd0c0ad14f6 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c @@ -4,7 +4,7 @@ * * Objects manager (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -67,23 +67,13 @@ * A pointer to the target glyph zone. */ FT_LOCAL_DEF( void ) - tt_glyphzone_done( TT_GlyphZone zone ) + tt_glyphzone_done( FT_Memory memory, + TT_GlyphZone zone ) { - FT_Memory memory = zone->memory; + FT_FREE( zone->org ); - - if ( memory ) - { - FT_FREE( zone->contours ); - FT_FREE( zone->tags ); - FT_FREE( zone->cur ); - FT_FREE( zone->org ); - FT_FREE( zone->orus ); - - zone->max_points = zone->n_points = 0; - zone->max_contours = zone->n_contours = 0; - zone->memory = NULL; - } + zone->n_points = 0; + zone->n_contours = 0; } @@ -119,23 +109,22 @@ TT_GlyphZone zone ) { FT_Error error; + FT_Long size = 3 * maxPoints * sizeof ( FT_Vector ) + + maxContours * sizeof ( FT_UShort ) + + maxPoints * sizeof ( FT_Byte ); - FT_ZERO( zone ); - zone->memory = memory; - - if ( FT_NEW_ARRAY( zone->org, maxPoints ) || - FT_NEW_ARRAY( zone->cur, maxPoints ) || - FT_NEW_ARRAY( zone->orus, maxPoints ) || - FT_NEW_ARRAY( zone->tags, maxPoints ) || - FT_NEW_ARRAY( zone->contours, maxContours ) ) + if ( !FT_ALLOC( zone->org, size ) ) { - tt_glyphzone_done( zone ); - } - else - { - zone->max_points = maxPoints; - zone->max_contours = maxContours; + zone->n_points = maxPoints; + zone->n_contours = maxContours; + + zone->cur = zone->org + maxPoints; + zone->orus = zone->cur + maxPoints; + zone->contours = (FT_UShort*)( zone->orus + maxPoints ); + zone->tags = (FT_Byte*)( zone->contours + maxContours ); + + zone->first_point = 0; } return error; @@ -488,8 +477,7 @@ int j, k; - FT_MEM_SET( num_matched_ids, 0, - sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES ); + FT_ARRAY_ZERO( num_matched_ids, TRICK_SFNT_IDS_NUM_FACES ); has_cvt = FALSE; has_fpgm = FALSE; has_prep = FALSE; @@ -787,7 +775,7 @@ FT_UInt instance_index = (FT_UInt)face_index >> 16; - if ( FT_HAS_MULTIPLE_MASTERS( ttface ) ) + if ( instance_index && FT_HAS_MULTIPLE_MASTERS( ttface ) ) { error = FT_Set_Named_Instance( ttface, instance_index ); if ( error ) @@ -885,75 +873,40 @@ * size :: * A handle to the size object. * - * pedantic :: - * Set if bytecode execution should be pedantic. - * * @Return: * FreeType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) - tt_size_run_fpgm( TT_Size size, - FT_Bool pedantic ) + tt_size_run_fpgm( TT_Size size ) { TT_Face face = (TT_Face)size->root.face; - TT_ExecContext exec; + TT_ExecContext exec = size->context; FT_Error error; - exec = size->context; - error = TT_Load_Context( exec, face, size ); if ( error ) return error; - exec->callTop = 0; - exec->top = 0; - - exec->period = 64; - exec->phase = 0; - exec->threshold = 0; - - exec->instruction_trap = FALSE; - exec->F_dot_P = 0x4000L; - - exec->pedantic_hinting = pedantic; - - { - FT_Size_Metrics* size_metrics = &exec->metrics; - TT_Size_Metrics* tt_metrics = &exec->tt_metrics; - - - size_metrics->x_ppem = 0; - size_metrics->y_ppem = 0; - size_metrics->x_scale = 0; - size_metrics->y_scale = 0; - - tt_metrics->ppem = 0; - tt_metrics->scale = 0; - tt_metrics->ratio = 0x10000L; - } - - /* allow font program execution */ - TT_Set_CodeRange( exec, - tt_coderange_font, - face->font_program, - (FT_Long)face->font_program_size ); - /* disable CVT and glyph programs coderange */ TT_Clear_CodeRange( exec, tt_coderange_cvt ); TT_Clear_CodeRange( exec, tt_coderange_glyph ); if ( face->font_program_size > 0 ) { - TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); + /* allow font program execution */ + TT_Set_CodeRange( exec, + tt_coderange_font, + face->font_program, + (FT_Long)face->font_program_size ); + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; FT_TRACE4(( "Executing `fpgm' table.\n" )); - error = face->interpreter( exec ); -#ifdef FT_DEBUG_LEVEL_TRACE - if ( error ) - FT_TRACE4(( " interpretation failed with error code 0x%x\n", - error )); -#endif + error = TT_Run_Context( exec, size ); + FT_TRACE4(( error ? " failed (error code 0x%x)\n" : "", + error )); } else error = FT_Err_Ok; @@ -979,212 +932,146 @@ * size :: * A handle to the size object. * - * pedantic :: - * Set if bytecode execution should be pedantic. - * * @Return: * FreeType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) - tt_size_run_prep( TT_Size size, - FT_Bool pedantic ) + tt_size_run_prep( TT_Size size ) { TT_Face face = (TT_Face)size->root.face; - TT_ExecContext exec; + TT_ExecContext exec = size->context; FT_Error error; FT_UInt i; - /* Scale the cvt values to the new ppem. */ - /* By default, we use the y ppem value for scaling. */ - FT_TRACE6(( "CVT values:\n" )); - for ( i = 0; i < size->cvt_size; i++ ) - { - /* Unscaled CVT values are already stored in 26.6 format. */ - /* Note that this scaling operation is very sensitive to rounding; */ - /* the integer division by 64 must be applied to the first argument. */ - size->cvt[i] = FT_MulFix( face->cvt[i] / 64, size->ttmetrics.scale ); - FT_TRACE6(( " %3d: %f (%f)\n", - i, (double)face->cvt[i] / 64, (double)size->cvt[i] / 64 )); - } - FT_TRACE6(( "\n" )); + /* set default GS, twilight points, and storage */ + /* before CV program can modify them. */ + size->GS = tt_default_graphics_state; - exec = size->context; + /* all twilight points are originally zero */ + FT_ARRAY_ZERO( size->twilight.org, size->twilight.n_points ); + FT_ARRAY_ZERO( size->twilight.cur, size->twilight.n_points ); error = TT_Load_Context( exec, face, size ); if ( error ) return error; - exec->callTop = 0; - exec->top = 0; + /* clear storage area */ + FT_ARRAY_ZERO( exec->storage, exec->storeSize ); - exec->instruction_trap = FALSE; - - exec->pedantic_hinting = pedantic; - - TT_Set_CodeRange( exec, - tt_coderange_cvt, - face->cvt_program, - (FT_Long)face->cvt_program_size ); + /* Scale the cvt values to the new ppem. */ + /* By default, we use the y ppem value for scaling. */ + FT_TRACE6(( "CVT values:\n" )); + for ( i = 0; i < exec->cvtSize; i++ ) + { + /* Unscaled CVT values are already stored in 26.6 format. */ + /* Note that this scaling operation is very sensitive to rounding; */ + /* the integer division by 64 must be applied to the first argument. */ + exec->cvt[i] = FT_MulFix( face->cvt[i] / 64, size->ttmetrics.scale ); + FT_TRACE6(( " %3u: %f (%f)\n", + i, (double)face->cvt[i] / 64, (double)exec->cvt[i] / 64 )); + } + FT_TRACE6(( "\n" )); TT_Clear_CodeRange( exec, tt_coderange_glyph ); if ( face->cvt_program_size > 0 ) { - TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + /* allow CV program execution */ + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + (FT_Long)face->cvt_program_size ); + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; FT_TRACE4(( "Executing `prep' table.\n" )); - error = face->interpreter( exec ); -#ifdef FT_DEBUG_LEVEL_TRACE - if ( error ) - FT_TRACE4(( " interpretation failed with error code 0x%x\n", - error )); -#endif + error = TT_Run_Context( exec, size ); + FT_TRACE4(( error ? " failed (error code 0x%x)\n" : "", + error )); } else error = FT_Err_Ok; size->cvt_ready = error; - /* UNDOCUMENTED! The MS rasterizer doesn't allow the following */ - /* graphics state variables to be modified by the CVT program. */ - - exec->GS.dualVector.x = 0x4000; - exec->GS.dualVector.y = 0; - exec->GS.projVector.x = 0x4000; - exec->GS.projVector.y = 0x0; - exec->GS.freeVector.x = 0x4000; - exec->GS.freeVector.y = 0x0; - - exec->GS.rp0 = 0; - exec->GS.rp1 = 0; - exec->GS.rp2 = 0; - - exec->GS.gep0 = 1; - exec->GS.gep1 = 1; - exec->GS.gep2 = 1; - - exec->GS.loop = 1; - - /* save as default graphics state */ - size->GS = exec->GS; - - TT_Save_Context( exec, size ); + if ( !error ) + TT_Save_Context( exec, size ); return error; } static void - tt_size_done_bytecode( FT_Size ftsize ) + tt_size_done_bytecode( TT_Size size ) { - TT_Size size = (TT_Size)ftsize; - TT_Face face = (TT_Face)ftsize->face; - FT_Memory memory = face->root.memory; + FT_Memory memory = size->root.face->memory; + TT_ExecContext exec = size->context; - if ( size->context ) + + if ( exec ) { - TT_Done_Context( size->context ); + FT_FREE( exec->stack ); + FT_FREE( exec->FDefs ); + + TT_Done_Context( exec ); size->context = NULL; } - FT_FREE( size->cvt ); - size->cvt_size = 0; - - /* free storage area */ - FT_FREE( size->storage ); - size->storage_size = 0; - /* twilight zone */ - tt_glyphzone_done( &size->twilight ); - - FT_FREE( size->function_defs ); - FT_FREE( size->instruction_defs ); - - size->num_function_defs = 0; - size->max_function_defs = 0; - size->num_instruction_defs = 0; - size->max_instruction_defs = 0; - - size->max_func = 0; - size->max_ins = 0; - - size->bytecode_ready = -1; - size->cvt_ready = -1; + tt_glyphzone_done( memory, &size->twilight ); } /* Initialize bytecode-related fields in the size object. */ /* We do this only if bytecode interpretation is really needed. */ - static FT_Error - tt_size_init_bytecode( FT_Size ftsize, + FT_LOCAL_DEF( FT_Error ) + tt_size_init_bytecode( TT_Size size, FT_Bool pedantic ) { FT_Error error; - TT_Size size = (TT_Size)ftsize; - TT_Face face = (TT_Face)ftsize->face; - FT_Memory memory = face->root.memory; + TT_Face face = (TT_Face)size->root.face; + FT_Memory memory = size->root.face->memory; FT_UShort n_twilight; TT_MaxProfile* maxp = &face->max_profile; + TT_ExecContext exec; - /* clean up bytecode related data */ - FT_FREE( size->function_defs ); - FT_FREE( size->instruction_defs ); - FT_FREE( size->cvt ); - FT_FREE( size->storage ); + exec = TT_New_Context( (TT_Driver)face->root.driver ); + if ( !exec ) + return FT_THROW( Could_Not_Find_Context ); - if ( size->context ) - TT_Done_Context( size->context ); - tt_glyphzone_done( &size->twilight ); + exec->pedantic_hinting = pedantic; - size->bytecode_ready = -1; - size->cvt_ready = -1; + exec->maxFDefs = maxp->maxFunctionDefs; + exec->maxIDefs = maxp->maxInstructionDefs; - size->context = TT_New_Context( (TT_Driver)face->root.driver ); - - size->max_function_defs = maxp->maxFunctionDefs; - size->max_instruction_defs = maxp->maxInstructionDefs; - - size->num_function_defs = 0; - size->num_instruction_defs = 0; - - size->max_func = 0; - size->max_ins = 0; - - size->cvt_size = face->cvt_size; - size->storage_size = maxp->maxStorage; - - /* Set default metrics */ - { - TT_Size_Metrics* tt_metrics = &size->ttmetrics; - - - tt_metrics->rotated = FALSE; - tt_metrics->stretched = FALSE; - - /* Set default engine compensation. Value 3 is not described */ - /* in the OpenType specification (as of Mai 2019), but Greg */ - /* says that MS handles it the same as `gray'. */ - /* */ - /* The Apple specification says that the compensation for */ - /* `gray' is always zero. FreeType doesn't do any */ - /* compensation at all. */ - tt_metrics->compensations[0] = 0; /* gray */ - tt_metrics->compensations[1] = 0; /* black */ - tt_metrics->compensations[2] = 0; /* white */ - tt_metrics->compensations[3] = 0; /* zero */ - } - - /* allocate function defs, instruction defs, cvt, and storage area */ - if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) || - FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) || - FT_NEW_ARRAY( size->cvt, size->cvt_size ) || - FT_NEW_ARRAY( size->storage, size->storage_size ) ) + if ( FT_NEW_ARRAY( exec->FDefs, exec->maxFDefs + exec->maxIDefs ) ) goto Exit; - /* reserve twilight zone */ + exec->IDefs = exec->FDefs + exec->maxFDefs; + + exec->numFDefs = 0; + exec->numIDefs = 0; + + exec->maxFunc = 0; + exec->maxIns = 0; + + /* XXX: We reserve a little more elements on the stack to deal */ + /* with broken fonts like arialbs, courbs, timesbs, etc. */ + exec->stackSize = maxp->maxStackElements + 32; + exec->storeSize = maxp->maxStorage; + exec->cvtSize = face->cvt_size; + + if ( FT_NEW_ARRAY( exec->stack, + exec->stackSize + + (FT_Long)( exec->storeSize + exec->cvtSize ) ) ) + goto Exit; + + /* reserve twilight zone and set GS before fpgm is executed, */ + /* just in case, even though fpgm should not touch them */ n_twilight = maxp->maxTwilightPoints; /* there are 4 phantom points (do we need this?) */ @@ -1194,20 +1081,12 @@ if ( error ) goto Exit; - size->twilight.n_points = n_twilight; + size->GS = tt_default_graphics_state; + size->cvt_ready = -1; + size->context = exec; - size->GS = tt_default_graphics_state; - - /* set `face->interpreter' according to the debug hook present */ - { - FT_Library library = face->root.driver->root.library; - - - face->interpreter = (TT_Interpreter) - library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; - if ( !face->interpreter ) - face->interpreter = (TT_Interpreter)TT_RunIns; - } + size->ttmetrics.rotated = FALSE; + size->ttmetrics.stretched = FALSE; /* Fine, now run the font program! */ @@ -1217,62 +1096,16 @@ /* to be executed just once; calling it again is completely useless */ /* and might even lead to extremely slow behaviour if it is malformed */ /* (containing an infinite loop, for example). */ - error = tt_size_run_fpgm( size, pedantic ); + error = tt_size_run_fpgm( size ); return error; Exit: if ( error ) - tt_size_done_bytecode( ftsize ); + tt_size_done_bytecode( size ); return error; } - - FT_LOCAL_DEF( FT_Error ) - tt_size_ready_bytecode( TT_Size size, - FT_Bool pedantic ) - { - FT_Error error = FT_Err_Ok; - - - if ( size->bytecode_ready < 0 ) - error = tt_size_init_bytecode( (FT_Size)size, pedantic ); - else - error = size->bytecode_ready; - - if ( error ) - goto Exit; - - /* rescale CVT when needed */ - if ( size->cvt_ready < 0 ) - { - FT_UShort i; - - - /* all twilight points are originally zero */ - for ( i = 0; i < size->twilight.n_points; i++ ) - { - size->twilight.org[i].x = 0; - size->twilight.org[i].y = 0; - size->twilight.cur[i].x = 0; - size->twilight.cur[i].y = 0; - } - - /* clear storage area */ - for ( i = 0; i < size->storage_size; i++ ) - size->storage[i] = 0; - - size->GS = tt_default_graphics_state; - - error = tt_size_run_prep( size, pedantic ); - } - else - error = size->cvt_ready; - - Exit: - return error; - } - #endif /* TT_USE_BYTECODE_INTERPRETER */ @@ -1300,11 +1133,9 @@ #ifdef TT_USE_BYTECODE_INTERPRETER size->bytecode_ready = -1; - size->cvt_ready = -1; #endif - size->ttmetrics.valid = FALSE; - size->strike_index = 0xFFFFFFFFUL; + size->strike_index = 0xFFFFFFFFUL; return error; } @@ -1325,14 +1156,11 @@ FT_LOCAL_DEF( void ) tt_size_done( FT_Size ttsize ) /* TT_Size */ { - TT_Size size = (TT_Size)ttsize; - - #ifdef TT_USE_BYTECODE_INTERPRETER - tt_size_done_bytecode( ttsize ); + tt_size_done_bytecode( (TT_Size)ttsize ); +#else + FT_UNUSED( ttsize ); #endif - - size->ttmetrics.valid = FALSE; } @@ -1353,21 +1181,13 @@ * function must take `FT_Size` as a result. The passed `FT_Size` is * expected to point to a `TT_Size`. */ - FT_LOCAL_DEF( FT_Error ) + FT_LOCAL_DEF( void ) tt_size_reset_height( FT_Size ft_size ) { TT_Size size = (TT_Size)ft_size; - TT_Face face = (TT_Face)size->root.face; + TT_Face face = (TT_Face)ft_size->face; FT_Size_Metrics* size_metrics = &size->hinted_metrics; - size->ttmetrics.valid = FALSE; - - /* copy the result from base layer */ - *size_metrics = size->root.metrics; - - if ( size_metrics->x_ppem < 1 || size_metrics->y_ppem < 1 ) - return FT_THROW( Invalid_PPem ); - /* This bit flag, if set, indicates that the ppems must be */ /* rounded to integers. Nearly all TrueType fonts have this bit */ /* set, as hinting won't work really well otherwise. */ @@ -1385,10 +1205,6 @@ FT_MulFix( face->root.height, size_metrics->y_scale ) ); } - - size->ttmetrics.valid = TRUE; - - return FT_Err_Ok; } @@ -1408,14 +1224,20 @@ FT_LOCAL_DEF( FT_Error ) tt_size_reset( TT_Size size ) { - FT_Error error; TT_Face face = (TT_Face)size->root.face; FT_Size_Metrics* size_metrics = &size->hinted_metrics; - error = tt_size_reset_height( (FT_Size)size ); - if ( error ) - return error; + /* invalidate the size object first */ + size->ttmetrics.ppem = 0; + + if ( size->root.metrics.x_ppem == 0 || size->root.metrics.y_ppem == 0 ) + return FT_THROW( Invalid_PPem ); + + /* copy the result from base layer */ + *size_metrics = size->root.metrics; + + tt_size_reset_height( (FT_Size)size ); if ( face->header.Flags & 8 ) { diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h index 9c36ca78362..28d6c7d855f 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h @@ -4,7 +4,7 @@ * * Objects manager (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -53,6 +53,8 @@ FT_BEGIN_HEADER typedef FT_GlyphSlot TT_GlyphSlot; +#ifdef TT_USE_BYTECODE_INTERPRETER + /************************************************************************** * * @Struct: @@ -67,21 +69,27 @@ FT_BEGIN_HEADER FT_UShort rp1; FT_UShort rp2; + FT_UShort gep0; + FT_UShort gep1; + FT_UShort gep2; + FT_UnitVector dualVector; FT_UnitVector projVector; FT_UnitVector freeVector; FT_Long loop; - FT_F26Dot6 minimum_distance; FT_Int round_state; + FT_F26Dot6 compensation[4]; /* device-specific compensations */ - FT_Bool auto_flip; + /* default values below can be modified by 'fpgm' and 'prep' */ + FT_F26Dot6 minimum_distance; FT_F26Dot6 control_value_cutin; FT_F26Dot6 single_width_cutin; FT_F26Dot6 single_width_value; FT_UShort delta_base; FT_UShort delta_shift; + FT_Bool auto_flip; FT_Byte instruct_control; /* According to Greg Hitchcock from Microsoft, the `scan_control' */ /* variable as documented in the TrueType specification is a 32-bit */ @@ -90,17 +98,12 @@ FT_BEGIN_HEADER FT_Bool scan_control; FT_Int scan_type; - FT_UShort gep0; - FT_UShort gep1; - FT_UShort gep2; - } TT_GraphicsState; -#ifdef TT_USE_BYTECODE_INTERPRETER - FT_LOCAL( void ) - tt_glyphzone_done( TT_GlyphZone zone ); + tt_glyphzone_done( FT_Memory memory, + TT_GlyphZone zone ); FT_LOCAL( FT_Error ) tt_glyphzone_new( FT_Memory memory, @@ -112,73 +115,6 @@ FT_BEGIN_HEADER - /************************************************************************** - * - * EXECUTION SUBTABLES - * - * These sub-tables relate to instruction execution. - * - */ - - -#define TT_MAX_CODE_RANGES 3 - - - /************************************************************************** - * - * There can only be 3 active code ranges at once: - * - the Font Program - * - the CVT Program - * - a glyph's instructions set - */ - typedef enum TT_CodeRange_Tag_ - { - tt_coderange_none = 0, - tt_coderange_font, - tt_coderange_cvt, - tt_coderange_glyph - - } TT_CodeRange_Tag; - - - typedef struct TT_CodeRange_ - { - FT_Byte* base; - FT_Long size; - - } TT_CodeRange; - - typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES]; - - - /************************************************************************** - * - * Defines a function/instruction definition record. - */ - typedef struct TT_DefRecord_ - { - FT_Int range; /* in which code range is it located? */ - FT_Long start; /* where does it start? */ - FT_Long end; /* where does it end? */ - FT_UInt opc; /* function #, or instruction code */ - FT_Bool active; /* is it active? */ - - } TT_DefRecord, *TT_DefArray; - - - /************************************************************************** - * - * Subglyph transformation record. - */ - typedef struct TT_Transform_ - { - FT_Fixed xx, xy; /* transformation matrix coefficients */ - FT_Fixed yx, yy; - FT_F26Dot6 ox, oy; /* offsets */ - - } TT_Transform; - - /************************************************************************** * * A note regarding non-squared pixels: @@ -251,13 +187,9 @@ FT_BEGIN_HEADER FT_Long x_ratio; FT_Long y_ratio; - FT_UShort ppem; /* maximum ppem size */ FT_Long ratio; /* current ratio */ FT_Fixed scale; - - FT_F26Dot6 compensations[4]; /* device-specific compensations */ - - FT_Bool valid; + FT_UShort ppem; /* maximum ppem size */ FT_Bool rotated; /* `is the glyph rotated?'-flag */ FT_Bool stretched; /* `is the glyph stretched?'-flag */ @@ -288,27 +220,8 @@ FT_BEGIN_HEADER FT_Long point_size; /* for the `MPS' bytecode instruction */ - FT_UInt num_function_defs; /* number of function definitions */ - FT_UInt max_function_defs; - TT_DefArray function_defs; /* table of function definitions */ - - FT_UInt num_instruction_defs; /* number of ins. definitions */ - FT_UInt max_instruction_defs; - TT_DefArray instruction_defs; /* table of ins. definitions */ - - FT_UInt max_func; - FT_UInt max_ins; - - TT_CodeRangeTable codeRangeTable; - TT_GraphicsState GS; - FT_ULong cvt_size; /* the scaled control value table */ - FT_Long* cvt; - - FT_UShort storage_size; /* The storage area is now part of */ - FT_Long* storage; /* the instance */ - TT_GlyphZoneRec twilight; /* The instance's twilight zone */ TT_ExecContext context; @@ -375,20 +288,18 @@ FT_BEGIN_HEADER #ifdef TT_USE_BYTECODE_INTERPRETER FT_LOCAL( FT_Error ) - tt_size_run_fpgm( TT_Size size, - FT_Bool pedantic ); + tt_size_run_fpgm( TT_Size size ); FT_LOCAL( FT_Error ) - tt_size_run_prep( TT_Size size, - FT_Bool pedantic ); + tt_size_run_prep( TT_Size size ); FT_LOCAL( FT_Error ) - tt_size_ready_bytecode( TT_Size size, - FT_Bool pedantic ); + tt_size_init_bytecode( TT_Size size, + FT_Bool pedantic ); #endif /* TT_USE_BYTECODE_INTERPRETER */ - FT_LOCAL( FT_Error ) + FT_LOCAL( void ) tt_size_reset_height( FT_Size size ); FT_LOCAL( FT_Error ) diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c index 9505b5f179f..827454d8574 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -110,7 +110,7 @@ if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) { - FT_TRACE2(( "glyph count mismatch! loca: %ld, maxp: %ld\n", + FT_TRACE2(( "glyph count mismatch! loca: %lu, maxp: %ld\n", face->num_locations - 1, face->root.num_glyphs )); /* we only handle the case where `maxp' gives a larger value */ @@ -151,7 +151,7 @@ face->num_locations = (FT_ULong)face->root.num_glyphs + 1; table_len = new_loca_len; - FT_TRACE2(( "adjusting num_locations to %ld\n", + FT_TRACE2(( "adjusting num_locations to %lu\n", face->num_locations )); } else @@ -225,7 +225,7 @@ if ( pos1 > ttface->glyf_len ) { FT_TRACE1(( "tt_face_get_location:" - " too large offset (0x%08lx) found for glyph index %d,\n", + " too large offset (0x%08lx) found for glyph index %u,\n", pos1, gindex )); FT_TRACE1(( " " " exceeding the end of `glyf' table (0x%08lx)\n", @@ -240,17 +240,17 @@ if ( gindex == ttface->num_locations - 2 ) { FT_TRACE1(( "tt_face_get_location:" - " too large size (%ld bytes) found for glyph index %d,\n", + " too large size (%lu bytes) found for glyph index %u,\n", pos2 - pos1, gindex )); FT_TRACE1(( " " - " truncating at the end of `glyf' table to %ld bytes\n", + " truncating at the end of `glyf' table to %lu bytes\n", ttface->glyf_len - pos1 )); pos2 = ttface->glyf_len; } else { FT_TRACE1(( "tt_face_get_location:" - " too large offset (0x%08lx) found for glyph index %d,\n", + " too large offset (0x%08lx) found for glyph index %u,\n", pos2, gindex + 1 )); FT_TRACE1(( " " " exceeding the end of `glyf' table (0x%08lx)\n", @@ -419,7 +419,7 @@ if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) goto Exit; - FT_TRACE2(( "loaded, %12ld bytes\n", face->font_program_size )); + FT_TRACE2(( "loaded, %12lu bytes\n", face->font_program_size )); } Exit: @@ -482,7 +482,7 @@ if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) goto Exit; - FT_TRACE2(( "loaded, %12ld bytes\n", face->cvt_program_size )); + FT_TRACE2(( "loaded, %12lu bytes\n", face->cvt_program_size )); } Exit: diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h index bc32b58020c..bb4d3c9cc55 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.h @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c deleted file mode 100644 index d811beef0df..00000000000 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.c +++ /dev/null @@ -1,1013 +0,0 @@ -/**************************************************************************** - * - * ttsubpix.c - * - * TrueType Subpixel Hinting. - * - * Copyright (C) 2010-2023 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.TXT. By continuing to use, modify, or distribute - * this file you indicate that you have read the license and - * understand and accept it fully. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "ttsubpix.h" - - -#if defined( TT_USE_BYTECODE_INTERPRETER ) && \ - defined( TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY ) - - /************************************************************************** - * - * These rules affect how the TT Interpreter does hinting, with the - * goal of doing subpixel hinting by (in general) ignoring x moves. - * Some of these rules are fixes that go above and beyond the - * stated techniques in the MS whitepaper on Cleartype, due to - * artifacts in many glyphs. So, these rules make some glyphs render - * better than they do in the MS rasterizer. - * - * "" string or 0 int/char indicates to apply to all glyphs. - * "-" used as dummy placeholders, but any non-matching string works. - * - * Some of this could arguably be implemented in fontconfig, however: - * - * - Fontconfig can't set things on a glyph-by-glyph basis. - * - The tweaks that happen here are very low-level, from an average - * user's point of view and are best implemented in the hinter. - * - * The goal is to make the subpixel hinting techniques as generalized - * as possible across all fonts to prevent the need for extra rules such - * as these. - * - * The rule structure is designed so that entirely new rules can easily - * be added when a new compatibility feature is discovered. - * - * The rule structures could also use some enhancement to handle ranges. - * - * ****************** WORK IN PROGRESS ******************* - */ - - /* These are `classes' of fonts that can be grouped together and used in */ - /* rules below. A blank entry "" is required at the end of these! */ -#define FAMILY_CLASS_RULES_SIZE 7 - - static const SPH_Font_Class FAMILY_CLASS_Rules - [FAMILY_CLASS_RULES_SIZE] = - { - { "MS Legacy Fonts", - { "Aharoni", - "Andale Mono", - "Andalus", - "Angsana New", - "AngsanaUPC", - "Arabic Transparent", - "Arial Black", - "Arial Narrow", - "Arial Unicode MS", - "Arial", - "Batang", - "Browallia New", - "BrowalliaUPC", - "Comic Sans MS", - "Cordia New", - "CordiaUPC", - "Courier New", - "DFKai-SB", - "David Transparent", - "David", - "DilleniaUPC", - "Estrangelo Edessa", - "EucrosiaUPC", - "FangSong_GB2312", - "Fixed Miriam Transparent", - "FrankRuehl", - "Franklin Gothic Medium", - "FreesiaUPC", - "Garamond", - "Gautami", - "Georgia", - "Gulim", - "Impact", - "IrisUPC", - "JasmineUPC", - "KaiTi_GB2312", - "KodchiangUPC", - "Latha", - "Levenim MT", - "LilyUPC", - "Lucida Console", - "Lucida Sans Unicode", - "MS Gothic", - "MS Mincho", - "MV Boli", - "Mangal", - "Marlett", - "Microsoft Sans Serif", - "Mingliu", - "Miriam Fixed", - "Miriam Transparent", - "Miriam", - "Narkisim", - "Palatino Linotype", - "Raavi", - "Rod Transparent", - "Rod", - "Shruti", - "SimHei", - "Simplified Arabic Fixed", - "Simplified Arabic", - "Simsun", - "Sylfaen", - "Symbol", - "Tahoma", - "Times New Roman", - "Traditional Arabic", - "Trebuchet MS", - "Tunga", - "Verdana", - "Webdings", - "Wingdings", - "", - }, - }, - { "Core MS Legacy Fonts", - { "Arial Black", - "Arial Narrow", - "Arial Unicode MS", - "Arial", - "Comic Sans MS", - "Courier New", - "Garamond", - "Georgia", - "Impact", - "Lucida Console", - "Lucida Sans Unicode", - "Microsoft Sans Serif", - "Palatino Linotype", - "Tahoma", - "Times New Roman", - "Trebuchet MS", - "Verdana", - "", - }, - }, - { "Apple Legacy Fonts", - { "Geneva", - "Times", - "Monaco", - "Century", - "Chalkboard", - "Lobster", - "Century Gothic", - "Optima", - "Lucida Grande", - "Gill Sans", - "Baskerville", - "Helvetica", - "Helvetica Neue", - "", - }, - }, - { "Legacy Sans Fonts", - { "Andale Mono", - "Arial Unicode MS", - "Arial", - "Century Gothic", - "Comic Sans MS", - "Franklin Gothic Medium", - "Geneva", - "Lucida Console", - "Lucida Grande", - "Lucida Sans Unicode", - "Lucida Sans Typewriter", - "Microsoft Sans Serif", - "Monaco", - "Tahoma", - "Trebuchet MS", - "Verdana", - "", - }, - }, - - { "Misc Legacy Fonts", - { "Dark Courier", "", }, }, - { "Verdana Clones", - { "DejaVu Sans", - "Bitstream Vera Sans", "", }, }, - { "Verdana and Clones", - { "DejaVu Sans", - "Bitstream Vera Sans", - "Verdana", "", }, }, - }; - - - /* Define this to force natural (i.e. not bitmap-compatible) widths. */ - /* The default leans strongly towards natural widths except for a few */ - /* legacy fonts where a selective combination produces nicer results. */ -/* #define FORCE_NATURAL_WIDTHS */ - - - /* Define `classes' of styles that can be grouped together and used in */ - /* rules below. A blank entry "" is required at the end of these! */ -#define STYLE_CLASS_RULES_SIZE 5 - - static const SPH_Font_Class STYLE_CLASS_Rules - [STYLE_CLASS_RULES_SIZE] = - { - { "Regular Class", - { "Regular", - "Book", - "Medium", - "Roman", - "Normal", - "", - }, - }, - { "Regular/Italic Class", - { "Regular", - "Book", - "Medium", - "Italic", - "Oblique", - "Roman", - "Normal", - "", - }, - }, - { "Bold/BoldItalic Class", - { "Bold", - "Bold Italic", - "Black", - "", - }, - }, - { "Bold/Italic/BoldItalic Class", - { "Bold", - "Bold Italic", - "Black", - "Italic", - "Oblique", - "", - }, - }, - { "Regular/Bold Class", - { "Regular", - "Book", - "Medium", - "Normal", - "Roman", - "Bold", - "Black", - "", - }, - }, - }; - - - /* Force special legacy fixes for fonts. */ -#define COMPATIBILITY_MODE_RULES_SIZE 1 - - static const SPH_TweakRule COMPATIBILITY_MODE_Rules - [COMPATIBILITY_MODE_RULES_SIZE] = - { - { "Verdana Clones", 0, "", 0 }, - }; - - - /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */ -#define PIXEL_HINTING_RULES_SIZE 2 - - static const SPH_TweakRule PIXEL_HINTING_Rules - [PIXEL_HINTING_RULES_SIZE] = - { - /* these characters are almost always safe */ - { "Courier New", 12, "Italic", 'z' }, - { "Courier New", 11, "Italic", 'z' }, - }; - - - /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */ -#define DO_SHPIX_RULES_SIZE 1 - - static const SPH_TweakRule DO_SHPIX_Rules - [DO_SHPIX_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Skip Y moves that start with a point that is not on a Y pixel */ - /* boundary and don't move that point to a Y pixel boundary. */ -#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 4 - - static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules - [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] = - { - /* fix vwxyz thinness */ - { "Consolas", 0, "", 0 }, - /* Fix thin middle stems */ - { "Core MS Legacy Fonts", 0, "Regular", 0 }, - /* Cyrillic small letter I */ - { "Legacy Sans Fonts", 0, "", 0 }, - /* Fix artifacts with some Regular & Bold */ - { "Verdana Clones", 0, "", 0 }, - }; - - -#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 - - static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions - [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = - { - /* Fixes < and > */ - { "Courier New", 0, "Regular", 0 }, - }; - - - /* Skip Y moves that start with a point that is not on a Y pixel */ - /* boundary and don't move that point to a Y pixel boundary. */ -#define SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE 2 - - static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules - [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE] = - { - /* Maintain thickness of diagonal in 'N' */ - { "Times New Roman", 0, "Regular/Bold Class", 'N' }, - { "Georgia", 0, "Regular/Bold Class", 'N' }, - }; - - - /* Skip Y moves that move a point off a Y pixel boundary. */ -#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1 - - static const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules - [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - -#define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 - - static const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions - [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Round moves that don't move a point to a Y pixel boundary. */ -#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2 - - static const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules - [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] = - { - /* Droid font instructions don't snap Y to pixels */ - { "Droid Sans", 0, "Regular/Italic Class", 0 }, - { "Droid Sans Mono", 0, "", 0 }, - }; - - -#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 - - static const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions - [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Allow a Direct_Move along X freedom vector if matched. */ -#define ALLOW_X_DMOVE_RULES_SIZE 1 - - static const SPH_TweakRule ALLOW_X_DMOVE_Rules - [ALLOW_X_DMOVE_RULES_SIZE] = - { - /* Fixes vanishing diagonal in 4 */ - { "Verdana", 0, "Regular", '4' }, - }; - - - /* Return MS rasterizer version 35 if matched. */ -#define RASTERIZER_35_RULES_SIZE 8 - - static const SPH_TweakRule RASTERIZER_35_Rules - [RASTERIZER_35_RULES_SIZE] = - { - /* This seems to be the only way to make these look good */ - { "Times New Roman", 0, "Regular", 'i' }, - { "Times New Roman", 0, "Regular", 'j' }, - { "Times New Roman", 0, "Regular", 'm' }, - { "Times New Roman", 0, "Regular", 'r' }, - { "Times New Roman", 0, "Regular", 'a' }, - { "Times New Roman", 0, "Regular", 'n' }, - { "Times New Roman", 0, "Regular", 'p' }, - { "Times", 0, "", 0 }, - }; - - - /* Don't round to the subpixel grid. Round to pixel grid. */ -#define NORMAL_ROUND_RULES_SIZE 1 - - static const SPH_TweakRule NORMAL_ROUND_Rules - [NORMAL_ROUND_RULES_SIZE] = - { - /* Fix serif thickness for certain ppems */ - /* Can probably be generalized somehow */ - { "Courier New", 0, "", 0 }, - }; - - - /* Skip IUP instructions if matched. */ -#define SKIP_IUP_RULES_SIZE 1 - - static const SPH_TweakRule SKIP_IUP_Rules - [SKIP_IUP_RULES_SIZE] = - { - { "Arial", 13, "Regular", 'a' }, - }; - - - /* Skip MIAP Twilight hack if matched. */ -#define MIAP_HACK_RULES_SIZE 1 - - static const SPH_TweakRule MIAP_HACK_Rules - [MIAP_HACK_RULES_SIZE] = - { - { "Geneva", 12, "", 0 }, - }; - - - /* Skip DELTAP instructions if matched. */ -#define ALWAYS_SKIP_DELTAP_RULES_SIZE 23 - - static const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules - [ALWAYS_SKIP_DELTAP_RULES_SIZE] = - { - { "Georgia", 0, "Regular", 'k' }, - /* fix various problems with e in different versions */ - { "Trebuchet MS", 14, "Regular", 'e' }, - { "Trebuchet MS", 13, "Regular", 'e' }, - { "Trebuchet MS", 15, "Regular", 'e' }, - { "Trebuchet MS", 0, "Italic", 'v' }, - { "Trebuchet MS", 0, "Italic", 'w' }, - { "Trebuchet MS", 0, "Regular", 'Y' }, - { "Arial", 11, "Regular", 's' }, - /* prevent problems with '3' and others */ - { "Verdana", 10, "Regular", 0 }, - { "Verdana", 9, "Regular", 0 }, - /* Cyrillic small letter short I */ - { "Legacy Sans Fonts", 0, "", 0x438 }, - { "Legacy Sans Fonts", 0, "", 0x439 }, - { "Arial", 10, "Regular", '6' }, - { "Arial", 0, "Bold/BoldItalic Class", 'a' }, - /* Make horizontal stems consistent with the rest */ - { "Arial", 24, "Bold", 'a' }, - { "Arial", 25, "Bold", 'a' }, - { "Arial", 24, "Bold", 's' }, - { "Arial", 25, "Bold", 's' }, - { "Arial", 34, "Bold", 's' }, - { "Arial", 35, "Bold", 's' }, - { "Arial", 36, "Bold", 's' }, - { "Arial", 25, "Regular", 's' }, - { "Arial", 26, "Regular", 's' }, - }; - - - /* Always do DELTAP instructions if matched. */ -#define ALWAYS_DO_DELTAP_RULES_SIZE 1 - - static const SPH_TweakRule ALWAYS_DO_DELTAP_Rules - [ALWAYS_DO_DELTAP_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Don't allow ALIGNRP after IUP. */ -#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 1 - - static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules - [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] = - { - /* Prevent creation of dents in outline */ - { "-", 0, "", 0 }, - }; - - - /* Don't allow DELTAP after IUP. */ -#define NO_DELTAP_AFTER_IUP_RULES_SIZE 1 - - static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules - [NO_DELTAP_AFTER_IUP_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Don't allow CALL after IUP. */ -#define NO_CALL_AFTER_IUP_RULES_SIZE 1 - - static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules - [NO_CALL_AFTER_IUP_RULES_SIZE] = - { - /* Prevent creation of dents in outline */ - { "-", 0, "", 0 }, - }; - - - /* De-embolden these glyphs slightly. */ -#define DEEMBOLDEN_RULES_SIZE 9 - - static const SPH_TweakRule DEEMBOLDEN_Rules - [DEEMBOLDEN_RULES_SIZE] = - { - { "Courier New", 0, "Bold", 'A' }, - { "Courier New", 0, "Bold", 'W' }, - { "Courier New", 0, "Bold", 'w' }, - { "Courier New", 0, "Bold", 'M' }, - { "Courier New", 0, "Bold", 'X' }, - { "Courier New", 0, "Bold", 'K' }, - { "Courier New", 0, "Bold", 'x' }, - { "Courier New", 0, "Bold", 'z' }, - { "Courier New", 0, "Bold", 'v' }, - }; - - - /* Embolden these glyphs slightly. */ -#define EMBOLDEN_RULES_SIZE 2 - - static const SPH_TweakRule EMBOLDEN_Rules - [EMBOLDEN_RULES_SIZE] = - { - { "Courier New", 0, "Regular", 0 }, - { "Courier New", 0, "Italic", 0 }, - }; - - - /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7 */ - /* similar to Windows XP. */ -#define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12 - - static const SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules - [TIMES_NEW_ROMAN_HACK_RULES_SIZE] = - { - { "Times New Roman", 16, "Italic", '2' }, - { "Times New Roman", 16, "Italic", '5' }, - { "Times New Roman", 16, "Italic", '7' }, - { "Times New Roman", 16, "Regular", '2' }, - { "Times New Roman", 16, "Regular", '5' }, - { "Times New Roman", 16, "Regular", '7' }, - { "Times New Roman", 17, "Italic", '2' }, - { "Times New Roman", 17, "Italic", '5' }, - { "Times New Roman", 17, "Italic", '7' }, - { "Times New Roman", 17, "Regular", '2' }, - { "Times New Roman", 17, "Regular", '5' }, - { "Times New Roman", 17, "Regular", '7' }, - }; - - - /* This fudges distance on 2 to get rid of the vanishing stem issue. */ - /* A real solution to this is certainly welcome. */ -#define COURIER_NEW_2_HACK_RULES_SIZE 15 - - static const SPH_TweakRule COURIER_NEW_2_HACK_Rules - [COURIER_NEW_2_HACK_RULES_SIZE] = - { - { "Courier New", 10, "Regular", '2' }, - { "Courier New", 11, "Regular", '2' }, - { "Courier New", 12, "Regular", '2' }, - { "Courier New", 13, "Regular", '2' }, - { "Courier New", 14, "Regular", '2' }, - { "Courier New", 15, "Regular", '2' }, - { "Courier New", 16, "Regular", '2' }, - { "Courier New", 17, "Regular", '2' }, - { "Courier New", 18, "Regular", '2' }, - { "Courier New", 19, "Regular", '2' }, - { "Courier New", 20, "Regular", '2' }, - { "Courier New", 21, "Regular", '2' }, - { "Courier New", 22, "Regular", '2' }, - { "Courier New", 23, "Regular", '2' }, - { "Courier New", 24, "Regular", '2' }, - }; - - -#ifndef FORCE_NATURAL_WIDTHS - - /* Use compatible widths with these glyphs. Compatible widths is always */ - /* on when doing B/W TrueType instructing, but is used selectively here, */ - /* typically on glyphs with 3 or more vertical stems. */ -#define COMPATIBLE_WIDTHS_RULES_SIZE 38 - - static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules - [COMPATIBLE_WIDTHS_RULES_SIZE] = - { - { "Arial Unicode MS", 12, "Regular Class", 'm' }, - { "Arial Unicode MS", 14, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Arial", 10, "Regular Class", 0x448 }, - { "Arial", 11, "Regular Class", 'm' }, - { "Arial", 12, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Arial", 12, "Regular Class", 0x448 }, - { "Arial", 13, "Regular Class", 0x448 }, - { "Arial", 14, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Arial", 14, "Regular Class", 0x448 }, - { "Arial", 15, "Regular Class", 0x448 }, - { "Arial", 17, "Regular Class", 'm' }, - { "DejaVu Sans", 15, "Regular Class", 0 }, - { "Microsoft Sans Serif", 11, "Regular Class", 0 }, - { "Microsoft Sans Serif", 12, "Regular Class", 0 }, - { "Segoe UI", 11, "Regular Class", 0 }, - { "Monaco", 0, "Regular Class", 0 }, - { "Segoe UI", 12, "Regular Class", 'm' }, - { "Segoe UI", 14, "Regular Class", 'm' }, - { "Tahoma", 11, "Regular Class", 0 }, - { "Times New Roman", 16, "Regular Class", 'c' }, - { "Times New Roman", 16, "Regular Class", 'm' }, - { "Times New Roman", 16, "Regular Class", 'o' }, - { "Times New Roman", 16, "Regular Class", 'w' }, - { "Trebuchet MS", 11, "Regular Class", 0 }, - { "Trebuchet MS", 12, "Regular Class", 0 }, - { "Trebuchet MS", 14, "Regular Class", 0 }, - { "Trebuchet MS", 15, "Regular Class", 0 }, - { "Ubuntu", 12, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Verdana", 10, "Regular Class", 0x448 }, - { "Verdana", 11, "Regular Class", 0x448 }, - { "Verdana and Clones", 12, "Regular Class", 'i' }, - { "Verdana and Clones", 12, "Regular Class", 'j' }, - { "Verdana and Clones", 12, "Regular Class", 'l' }, - { "Verdana and Clones", 12, "Regular Class", 'm' }, - { "Verdana and Clones", 13, "Regular Class", 'i' }, - { "Verdana and Clones", 13, "Regular Class", 'j' }, - { "Verdana and Clones", 13, "Regular Class", 'l' }, - { "Verdana and Clones", 14, "Regular Class", 'm' }, - }; - - - /* Scaling slightly in the x-direction prior to hinting results in */ - /* more visually pleasing glyphs in certain cases. */ - /* This sometimes needs to be coordinated with compatible width rules. */ - /* A value of 1000 corresponds to a scaled value of 1.0. */ - -#define X_SCALING_RULES_SIZE 50 - - static const SPH_ScaleRule X_SCALING_Rules[X_SCALING_RULES_SIZE] = - { - { "DejaVu Sans", 12, "Regular Class", 'm', 950 }, - { "Verdana and Clones", 12, "Regular Class", 'a', 1100 }, - { "Verdana and Clones", 13, "Regular Class", 'a', 1050 }, - { "Arial", 11, "Regular Class", 'm', 975 }, - { "Arial", 12, "Regular Class", 'm', 1050 }, - /* Cyrillic small letter el */ - { "Arial", 13, "Regular Class", 0x43B, 950 }, - { "Arial", 13, "Regular Class", 'o', 950 }, - { "Arial", 13, "Regular Class", 'e', 950 }, - { "Arial", 14, "Regular Class", 'm', 950 }, - /* Cyrillic small letter el */ - { "Arial", 15, "Regular Class", 0x43B, 925 }, - { "Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100 }, - { "Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050 }, - { "Bitstream Vera Sans", 16, "Regular Class", 0, 1050 }, - { "Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050 }, - { "DejaVu Sans", 12, "Regular Class", 'l', 975 }, - { "DejaVu Sans", 12, "Regular Class", 'i', 975 }, - { "DejaVu Sans", 12, "Regular Class", 'j', 975 }, - { "DejaVu Sans", 13, "Regular Class", 'l', 950 }, - { "DejaVu Sans", 13, "Regular Class", 'i', 950 }, - { "DejaVu Sans", 13, "Regular Class", 'j', 950 }, - { "DejaVu Sans", 10, "Regular/Italic Class", 0, 1100 }, - { "DejaVu Sans", 12, "Regular/Italic Class", 0, 1050 }, - { "Georgia", 10, "", 0, 1050 }, - { "Georgia", 11, "", 0, 1100 }, - { "Georgia", 12, "", 0, 1025 }, - { "Georgia", 13, "", 0, 1050 }, - { "Georgia", 16, "", 0, 1050 }, - { "Georgia", 17, "", 0, 1030 }, - { "Liberation Sans", 12, "Regular Class", 'm', 1100 }, - { "Lucida Grande", 11, "Regular Class", 'm', 1100 }, - { "Microsoft Sans Serif", 11, "Regular Class", 'm', 950 }, - { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1050 }, - { "Segoe UI", 12, "Regular Class", 'H', 1050 }, - { "Segoe UI", 12, "Regular Class", 'm', 1050 }, - { "Segoe UI", 14, "Regular Class", 'm', 1050 }, - { "Tahoma", 11, "Regular Class", 'i', 975 }, - { "Tahoma", 11, "Regular Class", 'l', 975 }, - { "Tahoma", 11, "Regular Class", 'j', 900 }, - { "Tahoma", 11, "Regular Class", 'm', 918 }, - { "Verdana", 10, "Regular/Italic Class", 0, 1100 }, - { "Verdana", 12, "Regular Class", 'm', 975 }, - { "Verdana", 12, "Regular/Italic Class", 0, 1050 }, - { "Verdana", 13, "Regular/Italic Class", 'i', 950 }, - { "Verdana", 13, "Regular/Italic Class", 'j', 950 }, - { "Verdana", 13, "Regular/Italic Class", 'l', 950 }, - { "Verdana", 16, "Regular Class", 0, 1050 }, - { "Verdana", 9, "Regular/Italic Class", 0, 1050 }, - { "Times New Roman", 16, "Regular Class", 'm', 918 }, - { "Trebuchet MS", 11, "Regular Class", 'm', 800 }, - { "Trebuchet MS", 12, "Regular Class", 'm', 800 }, - }; - -#else - -#define COMPATIBLE_WIDTHS_RULES_SIZE 1 - - static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules - [COMPATIBLE_WIDTHS_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - -#define X_SCALING_RULES_SIZE 1 - - static const SPH_ScaleRule X_SCALING_Rules - [X_SCALING_RULES_SIZE] = - { - { "-", 0, "", 0, 1000 }, - }; - -#endif /* FORCE_NATURAL_WIDTHS */ - - - static FT_Bool - is_member_of_family_class( const FT_String* detected_font_name, - const FT_String* rule_font_name ) - { - FT_UInt i, j; - - - /* Does font name match rule family? */ - if ( ft_strcmp( detected_font_name, rule_font_name ) == 0 ) - return TRUE; - - /* Is font name a wildcard ""? */ - if ( ft_strcmp( rule_font_name, "" ) == 0 ) - return TRUE; - - /* Is font name contained in a class list? */ - for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ ) - { - if ( ft_strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 ) - { - for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) - { - if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 ) - continue; - if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], - detected_font_name ) == 0 ) - return TRUE; - } - } - } - - return FALSE; - } - - - static FT_Bool - is_member_of_style_class( const FT_String* detected_font_style, - const FT_String* rule_font_style ) - { - FT_UInt i, j; - - - /* Does font style match rule style? */ - if ( ft_strcmp( detected_font_style, rule_font_style ) == 0 ) - return TRUE; - - /* Is font style a wildcard ""? */ - if ( ft_strcmp( rule_font_style, "" ) == 0 ) - return TRUE; - - /* Is font style contained in a class list? */ - for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ ) - { - if ( ft_strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 ) - { - for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) - { - if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 ) - continue; - if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], - detected_font_style ) == 0 ) - return TRUE; - } - } - } - - return FALSE; - } - - - FT_LOCAL_DEF( FT_Bool ) - sph_test_tweak( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index, - const SPH_TweakRule* rule, - FT_UInt num_rules ) - { - FT_UInt i; - - - /* rule checks may be able to be optimized further */ - for ( i = 0; i < num_rules; i++ ) - { - if ( family && - ( is_member_of_family_class ( family, rule[i].family ) ) ) - if ( rule[i].ppem == 0 || - rule[i].ppem == ppem ) - if ( style && - is_member_of_style_class ( style, rule[i].style ) ) - if ( rule[i].glyph == 0 || - FT_Get_Char_Index( (FT_Face)face, - rule[i].glyph ) == glyph_index ) - return TRUE; - } - - return FALSE; - } - - - static FT_UInt - scale_test_tweak( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index, - const SPH_ScaleRule* rule, - FT_UInt num_rules ) - { - FT_UInt i; - - - /* rule checks may be able to be optimized further */ - for ( i = 0; i < num_rules; i++ ) - { - if ( family && - ( is_member_of_family_class ( family, rule[i].family ) ) ) - if ( rule[i].ppem == 0 || - rule[i].ppem == ppem ) - if ( style && - is_member_of_style_class( style, rule[i].style ) ) - if ( rule[i].glyph == 0 || - FT_Get_Char_Index( (FT_Face)face, - rule[i].glyph ) == glyph_index ) - return rule[i].scale; - } - - return 1000; - } - - - FT_LOCAL_DEF( FT_UInt ) - sph_test_tweak_x_scaling( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index ) - { - return scale_test_tweak( face, family, ppem, style, glyph_index, - X_SCALING_Rules, X_SCALING_RULES_SIZE ); - } - - -#define TWEAK_RULES( x ) \ - if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ - x##_Rules, x##_RULES_SIZE ) ) \ - loader->exec->sph_tweak_flags |= SPH_TWEAK_##x - -#define TWEAK_RULES_EXCEPTIONS( x ) \ - if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ - x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \ - loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x - - - FT_LOCAL_DEF( void ) - sph_set_tweaks( TT_Loader loader, - FT_UInt glyph_index ) - { - TT_Face face = loader->face; - FT_String* family = face->root.family_name; - FT_UInt ppem = loader->size->metrics->x_ppem; - FT_String* style = face->root.style_name; - - - /* don't apply rules if style isn't set */ - if ( !face->root.style_name ) - return; - -#ifdef SPH_DEBUG_MORE_VERBOSE - printf( "%s,%d,%s,%c=%d ", - family, ppem, style, glyph_index, glyph_index ); -#endif - - TWEAK_RULES( PIXEL_HINTING ); - - if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING ) - { - loader->exec->ignore_x_mode = FALSE; - return; - } - - TWEAK_RULES( ALLOW_X_DMOVE ); - TWEAK_RULES( ALWAYS_DO_DELTAP ); - TWEAK_RULES( ALWAYS_SKIP_DELTAP ); - TWEAK_RULES( DEEMBOLDEN ); - TWEAK_RULES( DO_SHPIX ); - TWEAK_RULES( EMBOLDEN ); - TWEAK_RULES( MIAP_HACK ); - TWEAK_RULES( NORMAL_ROUND ); - TWEAK_RULES( NO_ALIGNRP_AFTER_IUP ); - TWEAK_RULES( NO_CALL_AFTER_IUP ); - TWEAK_RULES( NO_DELTAP_AFTER_IUP ); - TWEAK_RULES( RASTERIZER_35 ); - TWEAK_RULES( SKIP_IUP ); - - TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES ); - TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES ); - - TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP ); - - TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES ); - TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES ); - - TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES ); - TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES ); - - if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) - { - if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 ) - { - loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35; - loader->exec->size->cvt_ready = -1; - - tt_size_ready_bytecode( - loader->exec->size, - FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); - } - else - loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35; - } - else - { - if ( loader->exec->rasterizer_version != - SPH_OPTION_SET_RASTERIZER_VERSION ) - { - loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; - loader->exec->size->cvt_ready = -1; - - tt_size_ready_bytecode( - loader->exec->size, - FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); - } - else - loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; - } - - if ( IS_HINTED( loader->load_flags ) ) - { - TWEAK_RULES( TIMES_NEW_ROMAN_HACK ); - TWEAK_RULES( COURIER_NEW_2_HACK ); - } - - if ( sph_test_tweak( face, family, ppem, style, glyph_index, - COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) ) - loader->exec->face->sph_compatibility_mode = TRUE; - - - if ( IS_HINTED( loader->load_flags ) ) - { - if ( sph_test_tweak( face, family, ppem, style, glyph_index, - COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) ) - loader->exec->compatible_widths |= TRUE; - } - } - -#else /* !(TT_USE_BYTECODE_INTERPRETER && */ - /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */ - - /* ANSI C doesn't like empty source files */ - typedef int _tt_subpix_dummy; - -#endif /* !(TT_USE_BYTECODE_INTERPRETER && */ - /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */ - - -/* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h deleted file mode 100644 index 62af4c272d1..00000000000 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttsubpix.h +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** - * - * ttsubpix.h - * - * TrueType Subpixel Hinting. - * - * Copyright (C) 2010-2023 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.TXT. By continuing to use, modify, or distribute - * this file you indicate that you have read the license and - * understand and accept it fully. - * - */ - - -#ifndef TTSUBPIX_H_ -#define TTSUBPIX_H_ - -#include "ttobjs.h" -#include "ttinterp.h" - - -FT_BEGIN_HEADER - - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - /************************************************************************** - * - * ID flags to identify special functions at FDEF and runtime. - * - */ -#define SPH_FDEF_INLINE_DELTA_1 0x0000001 -#define SPH_FDEF_INLINE_DELTA_2 0x0000002 -#define SPH_FDEF_DIAGONAL_STROKE 0x0000004 -#define SPH_FDEF_VACUFORM_ROUND_1 0x0000008 -#define SPH_FDEF_TTFAUTOHINT_1 0x0000010 -#define SPH_FDEF_SPACING_1 0x0000020 -#define SPH_FDEF_SPACING_2 0x0000040 -#define SPH_FDEF_TYPEMAN_STROKES 0x0000080 -#define SPH_FDEF_TYPEMAN_DIAGENDCTRL 0x0000100 - - - /************************************************************************** - * - * Tweak flags that are set for each glyph by the below rules. - * - */ -#define SPH_TWEAK_ALLOW_X_DMOVE 0x0000001UL -#define SPH_TWEAK_ALWAYS_DO_DELTAP 0x0000002UL -#define SPH_TWEAK_ALWAYS_SKIP_DELTAP 0x0000004UL -#define SPH_TWEAK_COURIER_NEW_2_HACK 0x0000008UL -#define SPH_TWEAK_DEEMBOLDEN 0x0000010UL -#define SPH_TWEAK_DO_SHPIX 0x0000020UL -#define SPH_TWEAK_EMBOLDEN 0x0000040UL -#define SPH_TWEAK_MIAP_HACK 0x0000080UL -#define SPH_TWEAK_NORMAL_ROUND 0x0000100UL -#define SPH_TWEAK_NO_ALIGNRP_AFTER_IUP 0x0000200UL -#define SPH_TWEAK_NO_CALL_AFTER_IUP 0x0000400UL -#define SPH_TWEAK_NO_DELTAP_AFTER_IUP 0x0000800UL -#define SPH_TWEAK_PIXEL_HINTING 0x0001000UL -#define SPH_TWEAK_RASTERIZER_35 0x0002000UL -#define SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES 0x0004000UL -#define SPH_TWEAK_SKIP_IUP 0x0008000UL -#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES 0x0010000UL -#define SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES 0x0020000UL -#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK 0x0040000UL -#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP 0x0080000UL - - - FT_LOCAL( FT_Bool ) - sph_test_tweak( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index, - const SPH_TweakRule* rule, - FT_UInt num_rules ); - - FT_LOCAL( FT_UInt ) - sph_test_tweak_x_scaling( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index ); - - FT_LOCAL( void ) - sph_set_tweaks( TT_Loader loader, - FT_UInt glyph_index ); - - - /* These macros are defined absent a method for setting them */ -#define SPH_OPTION_BITMAP_WIDTHS FALSE -#define SPH_OPTION_SET_SUBPIXEL TRUE -#define SPH_OPTION_SET_GRAYSCALE FALSE -#define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE -#define SPH_OPTION_SET_RASTERIZER_VERSION 38 - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - -FT_END_HEADER - -#endif /* TTSUBPIX_H_ */ - - -/* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c index a63cd4dc48a..b1a0d23bed6 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.c @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h index 7f5cdda191f..92ff627dd0d 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1afm.h @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c index 8ed01914a5a..5ded7714021 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.c @@ -4,7 +4,7 @@ * * Type 1 driver interface (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h index 5ff52b55b1a..1cc3d24e7dd 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1driver.h @@ -4,7 +4,7 @@ * * High-level Type 1 driver interface (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h b/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h index 8aeb24ae188..46bddbc30fd 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1errors.h @@ -4,7 +4,7 @@ * * Type 1 error codes (specification only). * - * Copyright (C) 2001-2024 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c index c29e682510c..b9bc0b56ce8 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.c @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -70,8 +70,13 @@ /* For incremental fonts get the character data using the */ /* callback function. */ if ( inc ) + { + /* So `free_glyph_data` knows whether to free it. */ + char_string->pointer = NULL; + error = inc->funcs->get_glyph_data( inc->object, glyph_index, char_string ); + } else #endif /* FT_CONFIG_OPTION_INCREMENTAL */ @@ -155,6 +160,9 @@ decoder->builder.advance.y = INT_TO_FIXED( metrics.advance_v ); } + if ( error && inc ) + inc->funcs->free_glyph_data( inc->object, char_string ); + #endif /* FT_CONFIG_OPTION_INCREMENTAL */ return error; @@ -295,7 +303,7 @@ { advances[nn] = 0; - FT_TRACE5(( " idx %d: advance height 0 font units\n", + FT_TRACE5(( " idx %u: advance height 0 font units\n", first + nn )); } @@ -333,7 +341,7 @@ else advances[nn] = 0; - FT_TRACE5(( " idx %d: advance width %ld font unit%s\n", + FT_TRACE5(( " idx %u: advance width %ld font unit%s\n", first + nn, advances[nn], advances[nn] == 1 ? "" : "s" )); @@ -380,7 +388,7 @@ goto Exit; } - FT_TRACE1(( "T1_Load_Glyph: glyph index %d\n", glyph_index )); + FT_TRACE1(( "T1_Load_Glyph: glyph index %u\n", glyph_index )); FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); @@ -398,16 +406,12 @@ glyph->y_scale = 0x10000L; } - t1glyph->outline.n_points = 0; - t1glyph->outline.n_contours = 0; - hinting = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) && !( load_flags & FT_LOAD_NO_HINTING ) ); scaled = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); glyph->hint = hinting; glyph->scaled = scaled; - t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; error = decoder_funcs->init( &decoder, t1glyph->face, @@ -452,16 +456,12 @@ must_finish_decoder = FALSE; - /* now, set the metrics -- this is rather simple, as */ - /* the left side bearing is the xMin, and the top side */ - /* bearing the yMax */ if ( !error ) { - t1glyph->outline.flags &= FT_OUTLINE_OWNER; - t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; - - /* for composite glyphs, return only left side bearing and */ - /* advance width */ + /* now, set the metrics -- this is rather simple, as */ + /* the left side bearing is the xMin, and the top side */ + /* bearing the yMax; for composite glyphs, return only */ + /* left side bearing and advance width */ if ( load_flags & FT_LOAD_NO_RECURSE ) { FT_Slot_Internal internal = t1glyph->internal; @@ -482,6 +482,13 @@ FT_Glyph_Metrics* metrics = &t1glyph->metrics; + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + + t1glyph->outline.flags &= FT_OUTLINE_OWNER; + t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + if ( t1size && t1size->metrics.y_ppem < 24 ) + t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + /* copy the _unscaled_ advance width */ metrics->horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); @@ -504,11 +511,6 @@ FIXED_TO_INT( decoder.builder.advance.y ); } - t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; - - if ( t1size && t1size->metrics.y_ppem < 24 ) - t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - #if 1 /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h index 17a6a5941e3..6bedd132c5f 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1gload.h @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c index ee7fb42a517..0f11445bef0 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c @@ -4,7 +4,7 @@ * * Type 1 font loader (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -471,7 +471,7 @@ nc = num_coords; if ( num_coords > blend->num_axis ) { - FT_TRACE2(( "T1_Get_MM_Blend: only using first %d of %d coordinates\n", + FT_TRACE2(( "T1_Get_MM_Blend: only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } @@ -640,7 +640,7 @@ { FT_UNUSED( instance_index ); - return T1_Set_MM_Blend( face, 0, NULL ); + return T1_Set_MM_WeightVector( face, 0, NULL ); } @@ -691,7 +691,7 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "T1_Get_Var_Design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h index a45efa7cb7b..2cd8241968d 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.h @@ -4,7 +4,7 @@ * * Type 1 font loader (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c index b1b27c31fe3..7f25208f875 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.c @@ -4,7 +4,7 @@ * * Type 1 objects manager (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h index 3809370c1e0..6c71977c154 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1objs.h @@ -4,7 +4,7 @@ * * Type 1 objects manager (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c index 3717ea7c572..ef643e298f4 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c @@ -4,7 +4,7 @@ * * Type 1 parser (body). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h index a0a2134d45c..f4ad426e9e1 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.h @@ -4,7 +4,7 @@ * * Type 1 parser (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h b/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h index 5a3d2f1ef08..c3736cd42c0 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1tokens.h @@ -4,7 +4,7 @@ * * Type 1 tokenizer (specification). * - * Copyright (C) 1996-2024 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/test/jdk/javax/swing/text/html/CSS/8231286/HtmlFontSizeTest.java b/test/jdk/javax/swing/text/html/CSS/8231286/HtmlFontSizeTest.java index 9bdf4dbfae8..eea0a969e77 100644 --- a/test/jdk/javax/swing/text/html/CSS/8231286/HtmlFontSizeTest.java +++ b/test/jdk/javax/swing/text/html/CSS/8231286/HtmlFontSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,8 @@ public class HtmlFontSizeTest { htmlPane.setEditorKit(kit); String htmlString = "\n" - + "\n" - + "

This should be 16 pt.

\n" + + "\n" + + "

This should be 32 pt.

\n" + "\n" + ""; @@ -71,10 +71,16 @@ public class HtmlFontSizeTest { System.out.println("size with W3C:" + w3cFrameSize); System.out.println("size without W3C:" + stdFrameSize); - float ratio = (float)w3cFrameSize.width / (float)stdFrameSize.width; - System.out.println("w3cFrameSize.width/stdFrameSize.width " + ratio); + float widthRatio = (float)w3cFrameSize.width / (float)stdFrameSize.width; + System.out.println("w3cFrameSize.width/stdFrameSize.width " + widthRatio); - if (!"1.3".equals(String.format(Locale.ENGLISH, "%.1f", ratio))) { + float heightRatio = (float)w3cFrameSize.height / (float)stdFrameSize.height; + System.out.println("w3cFrameSize.height/stdFrameSize.height " + heightRatio); + + float avgRatio = (widthRatio + heightRatio) / 2.0f; + System.out.println("Average ratio of two dimensions " + avgRatio); + + if (!"1.3".equals(String.format(Locale.ENGLISH, "%.1f", avgRatio))) { throw new RuntimeException("HTML font size too large with high-DPI scaling and W3C_LENGTH_UNITS"); } } From 667404948c1c967daf6e274c61b9d1b1bd0827d4 Mon Sep 17 00:00:00 2001 From: Oli Gillespie Date: Tue, 3 Mar 2026 10:05:14 +0000 Subject: [PATCH 007/655] 8378963: Test test/jdk/java/lang/management/RuntimeMXBean/InputArgument.java#id4 failed Reviewed-by: kevinw, dholmes --- .../jdk/java/lang/management/RuntimeMXBean/InputArgument.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/lang/management/RuntimeMXBean/InputArgument.java b/test/jdk/java/lang/management/RuntimeMXBean/InputArgument.java index 0e7609b86ed..8f0ed8e48af 100644 --- a/test/jdk/java/lang/management/RuntimeMXBean/InputArgument.java +++ b/test/jdk/java/lang/management/RuntimeMXBean/InputArgument.java @@ -69,7 +69,7 @@ * * @run driver InputArgument generateFlagsFile * @run main/othervm -XX:+UseFastJNIAccessors -XX:Flags=InputArgument.flags InputArgument - * -XX:+UseFastJNIAccessors -XX:-UseG1GC -XX:+UseParallelGC -XX:MaxHeapSize=100M + * -XX:+UseFastJNIAccessors -XX:+PrintWarnings -XX:-PrintCommandLineFlags -XX:ErrorLogTimeout=100 */ import java.lang.management.*; @@ -116,6 +116,6 @@ public class InputArgument { private static void generateFlagsFile() throws Exception { // 3 types of flag; both boolean cases and 1 numeric Files.writeString(Paths.get("", "InputArgument.flags"), - String.format("-UseG1GC%n+UseParallelGC%nMaxHeapSize=100M%n")); + String.format("+PrintWarnings%n-PrintCommandLineFlags%nErrorLogTimeout=100%n")); } } From b28568f5d8308170c018651ea1c87c2b8f36acb2 Mon Sep 17 00:00:00 2001 From: Vic Wang Date: Tue, 3 Mar 2026 10:41:47 +0000 Subject: [PATCH 008/655] 8367478: Improve UseAVX setting and add cpu descriptions for zhaoxin processors Reviewed-by: jiefu, dholmes --- src/hotspot/cpu/x86/vm_version_x86.cpp | 40 ++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 78d6dec08cf..b352de77d6f 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -958,9 +958,17 @@ void VM_Version::get_processor_features() { if (UseSSE < 1) _features.clear_feature(CPU_SSE); - //since AVX instructions is slower than SSE in some ZX cpus, force USEAVX=0. - if (is_zx() && ((cpu_family() == 6) || (cpu_family() == 7))) { - UseAVX = 0; + // ZX cpus specific settings + if (is_zx() && FLAG_IS_DEFAULT(UseAVX)) { + if (cpu_family() == 7) { + if (extended_cpu_model() == 0x5B || extended_cpu_model() == 0x6B) { + UseAVX = 1; + } else if (extended_cpu_model() == 0x1B || extended_cpu_model() == 0x3B) { + UseAVX = 0; + } + } else if (cpu_family() == 6) { + UseAVX = 0; + } } // UseSSE is set to the smaller of what hardware supports and what @@ -2623,6 +2631,23 @@ const char* VM_Version::cpu_family_description(void) { return _family_id_intel[cpu_family_id]; } } + if (is_zx()) { + int cpu_model_id = extended_cpu_model(); + if (cpu_family_id == 7) { + switch (cpu_model_id) { + case 0x1B: + return "wudaokou"; + case 0x3B: + return "lujiazui"; + case 0x5B: + return "yongfeng"; + case 0x6B: + return "shijidadao"; + } + } else if (cpu_family_id == 6) { + return "zhangjiang"; + } + } if (is_hygon()) { return "Dhyana"; } @@ -2642,6 +2667,9 @@ int VM_Version::cpu_type_description(char* const buf, size_t buf_len) { } else if (is_amd()) { cpu_type = "AMD"; x64 = cpu_is_em64t() ? " AMD64" : ""; + } else if (is_zx()) { + cpu_type = "Zhaoxin"; + x64 = cpu_is_em64t() ? " x86_64" : ""; } else if (is_hygon()) { cpu_type = "Hygon"; x64 = cpu_is_em64t() ? " AMD64" : ""; @@ -3259,6 +3287,12 @@ int VM_Version::allocate_prefetch_distance(bool use_watermark_prefetch) { } else { return 128; // Athlon } + } else if (is_zx()) { + if (supports_sse2()) { + return 256; + } else { + return 128; + } } else { // Intel if (supports_sse3() && is_intel_server_family()) { if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus From 7dc97af89f0965ff9e0fa38426adcfc8c69c34ea Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 3 Mar 2026 12:37:05 +0000 Subject: [PATCH 009/655] 8378905: RISC-V: fastdebug build fails after JDK-8377554 Reviewed-by: fyang, wenanjian --- src/hotspot/cpu/riscv/riscv.ad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 730dd68dd88..ed6e8db0606 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -2274,7 +2274,7 @@ encode %{ } else if (rtype == relocInfo::metadata_type) { __ mov_metadata(dst_reg, (Metadata*)con); } else { - assert(rtype == relocInfo::none, "unexpected reloc type"); + assert(rtype == relocInfo::none || rtype == relocInfo::external_word_type, "unexpected reloc type"); __ mv(dst_reg, $src$$constant); } } From 6cf8b2ea2fb34b2e63a44d74ffe0495669ea5690 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 3 Mar 2026 13:26:20 +0000 Subject: [PATCH 010/655] 8378845: Add NoSafepointVerifier to CriticalSection classes Reviewed-by: dholmes, iwalulya --- src/hotspot/share/utilities/globalCounter.inline.hpp | 7 +++++-- src/hotspot/share/utilities/singleWriterSynchronizer.hpp | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/utilities/globalCounter.inline.hpp b/src/hotspot/share/utilities/globalCounter.inline.hpp index ed37b8a878d..0d05096716a 100644 --- a/src/hotspot/share/utilities/globalCounter.inline.hpp +++ b/src/hotspot/share/utilities/globalCounter.inline.hpp @@ -29,6 +29,7 @@ #include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" +#include "runtime/safepointVerifiers.hpp" inline GlobalCounter::CSContext GlobalCounter::critical_section_begin(Thread *thread) { @@ -53,11 +54,13 @@ GlobalCounter::critical_section_end(Thread *thread, CSContext context) { } class GlobalCounter::CriticalSection { - private: + NoSafepointVerifier _nsv; Thread* _thread; CSContext _context; - public: + +public: inline CriticalSection(Thread* thread) : + _nsv(), _thread(thread), _context(GlobalCounter::critical_section_begin(_thread)) {} diff --git a/src/hotspot/share/utilities/singleWriterSynchronizer.hpp b/src/hotspot/share/utilities/singleWriterSynchronizer.hpp index 450c7e89233..c21c9d4ee5e 100644 --- a/src/hotspot/share/utilities/singleWriterSynchronizer.hpp +++ b/src/hotspot/share/utilities/singleWriterSynchronizer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "runtime/atomic.hpp" +#include "runtime/safepointVerifiers.hpp" #include "runtime/semaphore.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -101,12 +102,14 @@ inline void SingleWriterSynchronizer::exit(uint enter_value) { } class SingleWriterSynchronizer::CriticalSection : public StackObj { + NoSafepointVerifier _nsv; SingleWriterSynchronizer* _synchronizer; uint _enter_value; public: // Enter synchronizer's critical section. explicit CriticalSection(SingleWriterSynchronizer* synchronizer) : + _nsv(), _synchronizer(synchronizer), _enter_value(synchronizer->enter()) {} From 364fd0e37e05b98042db9c7c140c5ed6d78b50e0 Mon Sep 17 00:00:00 2001 From: Oli Gillespie Date: Tue, 3 Mar 2026 15:23:08 +0000 Subject: [PATCH 011/655] 8378971: Test jdk/jfr/event/runtime/TestVMInfoEvent.java fails after JDK-8378110 (RuntimeMXBean.getInputArguments()) Reviewed-by: syan, kevinw --- .../jdk/jfr/event/runtime/TestVMInfoEvent.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.java b/test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.java index 2571530a470..8cbc6ea2bb8 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestVMInfoEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,9 @@ import java.lang.management.RuntimeMXBean; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; -import java.util.stream.Collectors; +import java.util.Properties; +import jdk.internal.vm.VMSupport; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.Asserts; @@ -38,6 +39,7 @@ import jdk.test.lib.jfr.Events; /** * @test + * @modules java.base/jdk.internal.vm * @requires vm.flagless * @requires vm.gc == "Serial" | vm.gc == null * @requires vm.hasJFR @@ -69,13 +71,12 @@ public class TestVMInfoEvent { Asserts.fail(String.format("%s does not contain %s", jvmVersion, mbean.getVmVersion())); } - String jvmArgs = Events.assertField(event, "jvmArguments").notNull().getValue(); - String jvmFlags = Events.assertField(event, "jvmFlags").notNull().getValue(); Long pid = Events.assertField(event, "pid").atLeast(0L).getValue(); Asserts.assertEquals(pid, ProcessHandle.current().pid()); - String eventArgs = (jvmFlags.trim() + " " + jvmArgs).trim(); - String beanArgs = mbean.getInputArguments().stream().collect(Collectors.joining(" ")); - Asserts.assertEquals(eventArgs, beanArgs, "Wrong inputArgs"); + + Properties agentProps = VMSupport.getAgentProperties(); + Events.assertField(event, "jvmArguments").equal(agentProps.getProperty("sun.jvm.args")); + Events.assertField(event, "jvmFlags").equal(agentProps.getProperty("sun.jvm.flags")); final String javaCommand = mbean.getSystemProperties().get("sun.java.command"); Events.assertField(event, "javaArguments").equal(javaCommand); From 0ea7d890d98eda32912e9a8340020ee405042576 Mon Sep 17 00:00:00 2001 From: Raffaello Giulietti Date: Tue, 3 Mar 2026 16:57:09 +0000 Subject: [PATCH 012/655] 8377903: ArraysSupport::mismatch should document that they return the smallest index Reviewed-by: rriggs, vyazici --- .../classes/jdk/internal/util/ArraysSupport.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java b/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java index c220455e80b..3bd2486fa39 100644 --- a/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java +++ b/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java @@ -478,7 +478,7 @@ public class ArraysSupport { // Bytes /** - * Find the index of a mismatch between two arrays. + * Find the smallest index of a mismatch between two arrays. * *

This method does not perform bounds checks. It is the responsibility * of the caller to perform such bounds checks before calling this method. @@ -486,9 +486,9 @@ public class ArraysSupport { * @param a the first array to be tested for a mismatch * @param b the second array to be tested for a mismatch * @param length the number of bytes from each array to check - * @return the index of a mismatch between the two arrays, otherwise -1 if - * no mismatch. The index will be within the range of (inclusive) 0 to - * (exclusive) the smaller of the two array lengths. + * @return the smallest index of a mismatch between the two arrays, + * otherwise -1 if no mismatch. The index will be within the range of + * (inclusive) 0 to (exclusive) the smaller of the two array lengths. */ public static int mismatch(byte[] a, byte[] b, @@ -520,8 +520,8 @@ public class ArraysSupport { } /** - * Find the relative index of a mismatch between two arrays starting from - * given indexes. + * Find the smallest relative index of a mismatch between two arrays + * starting from given indexes. * *

This method does not perform bounds checks. It is the responsibility * of the caller to perform such bounds checks before calling this method. @@ -533,7 +533,7 @@ public class ArraysSupport { * @param bFromIndex the index of the first element (inclusive) in the * second array to be compared * @param length the number of bytes from each array to check - * @return the relative index of a mismatch between the two arrays, + * @return the smallest relative index of a mismatch between the two arrays, * otherwise -1 if no mismatch. The index will be within the range of * (inclusive) 0 to (exclusive) the smaller of the two array bounds. */ From df43ef915ab13714c7a191c6413494f97f9db8c2 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 3 Mar 2026 17:09:14 +0000 Subject: [PATCH 013/655] 8378883: Enable more vector reductions IR matching tests for RISC-V Reviewed-by: fyang --- .../loopopts/superword/TestReductions.java | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java index 9d674950499..5c085e6a3a3 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java @@ -1340,7 +1340,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.AND_REDUCTION_V, "> 0", IRNode.AND_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1357,7 +1357,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.OR_REDUCTION_V, "> 0", IRNode.OR_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1374,7 +1374,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.XOR_REDUCTION_V, "> 0", IRNode.XOR_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1391,7 +1391,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.ADD_REDUCTION_VI, "> 0", IRNode.ADD_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1408,7 +1408,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_REDUCTION_VI, "> 0", IRNode.MUL_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1425,7 +1425,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1442,7 +1442,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1460,7 +1460,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.AND_REDUCTION_V, "> 0", IRNode.AND_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1477,7 +1477,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.OR_REDUCTION_V, "> 0", IRNode.OR_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1494,7 +1494,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.XOR_REDUCTION_V, "> 0", IRNode.XOR_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1511,7 +1511,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.ADD_REDUCTION_VI, "> 0", IRNode.ADD_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1528,7 +1528,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_REDUCTION_VI, "> 0", IRNode.MUL_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1545,7 +1545,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1562,7 +1562,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1580,7 +1580,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.AND_REDUCTION_V, "> 0", IRNode.AND_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1597,7 +1597,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.OR_REDUCTION_V, "> 0", IRNode.OR_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1614,7 +1614,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.XOR_REDUCTION_V, "> 0", IRNode.XOR_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1631,7 +1631,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.ADD_REDUCTION_VI, "> 0", IRNode.ADD_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1648,7 +1648,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MUL_REDUCTION_VI, "> 0", IRNode.MUL_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1665,7 +1665,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1682,7 +1682,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VI, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_I, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1700,7 +1700,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.AND_REDUCTION_V, "> 0", IRNode.AND_VL, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1717,7 +1717,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.OR_REDUCTION_V, "> 0", IRNode.OR_VL, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1734,7 +1734,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.XOR_REDUCTION_V, "> 0", IRNode.XOR_VL, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1751,7 +1751,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_REDUCTION_VL, "> 0", IRNode.ADD_VL, "> 0"}, - applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -1799,7 +1799,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VL, "> 0"}, - applyIfCPUFeatureOr = {"avx512", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx512", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512", "false", "avx2", "true"}) @@ -1819,7 +1819,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VL, "> 0"}, - applyIfCPUFeatureOr = {"avx512", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx512", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512", "false", "avx2", "true"}) @@ -2207,7 +2207,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VF, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2224,7 +2224,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VF, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2284,7 +2284,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VF, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2301,7 +2301,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VF, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2361,7 +2361,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VF, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2378,7 +2378,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VF, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2444,7 +2444,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VD, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2461,7 +2461,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VD, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2521,7 +2521,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VD, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2538,7 +2538,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VD, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2598,7 +2598,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VD, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) @@ -2615,7 +2615,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VD, "> 0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) From 86800eb2b34bd6ea7a77e7a9ac2f7dbce89c11fb Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Tue, 3 Mar 2026 17:11:17 +0000 Subject: [PATCH 014/655] 8378723: Locale variant delimiter is unclear Reviewed-by: naoto --- src/java.base/share/classes/java/util/Locale.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index f45a52c14fa..682476d8082 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,7 +176,10 @@ import sun.util.locale.provider.TimeZoneNameUtility; * SUBTAG (('_'|'-') SUBTAG)*} where {@code SUBTAG = * [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}}. *

BCP 47 deviation: BCP 47 only - * uses hyphen ('-') as a delimiter, {@code Locale} is more lenient.
+ * uses hyphen ('-') as a delimiter and APIs provided by {@code Locale} which accept + * BCP 47 language tags expect as such. However, for backwards compatibility, + * {@link Locale.Builder#setVariant(String)} also accepts underscore ('_'). + * {@link Locale#of(String, String, String)} accepts only underscore ('_'). * *
Example: "polyton" (Polytonic Greek), "POSIX"
* From c13fdc044d188d2266b2a96c4d1803b014a00633 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 3 Mar 2026 19:09:03 +0000 Subject: [PATCH 015/655] 8378877: jpackage: improve rebranding of exe files on Windows Reviewed-by: almatvee --- .../internal/ExecutableRebrander.java | 142 +++++++++++------- .../jpackage/internal/WindowsDefender.java | 72 --------- .../jpackage/internal/WindowsRegistry.java | 130 ---------------- .../resources/WinResources.properties | 1 - 4 files changed, 87 insertions(+), 258 deletions(-) delete mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsDefender.java delete mode 100644 src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 05b87e6f449..ec2a96d4c7d 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,9 +40,11 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Properties; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Stream; import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.WinApplication; import jdk.jpackage.internal.model.WinExePackage; import jdk.jpackage.internal.model.WinLauncher; @@ -74,11 +76,11 @@ final class ExecutableRebrander { this.props = new HashMap<>(); - validateValueAndPut(this.props, Map.entry("COMPANY_NAME", props.vendor), "vendor"); - validateValueAndPut(this.props, Map.entry("FILE_DESCRIPTION",props.description), "description"); - validateValueAndPut(this.props, Map.entry("FILE_VERSION", props.version.toString()), "version"); - validateValueAndPut(this.props, Map.entry("LEGAL_COPYRIGHT", props.copyright), "copyright"); - validateValueAndPut(this.props, Map.entry("PRODUCT_NAME", props.name), "name"); + this.props.put("COMPANY_NAME", validateSingleLine(props.vendor)); + this.props.put("FILE_DESCRIPTION", validateSingleLine(props.description)); + this.props.put("FILE_VERSION", validateSingleLine(props.version.toString())); + this.props.put("LEGAL_COPYRIGHT", validateSingleLine(props.copyright)); + this.props.put("PRODUCT_NAME", validateSingleLine(props.name)); this.props.put("FIXEDFILEINFO_FILE_VERSION", toFixedFileVersion(props.version)); this.props.put("INTERNAL_NAME", props.executableName); @@ -90,7 +92,7 @@ final class ExecutableRebrander { UpdateResourceAction versionSwapper = resourceLock -> { if (versionSwap(resourceLock, propsArray) != 0) { - throw I18N.buildException().message("error.version-swap", target).create(RuntimeException::new); + throw new JPackageException(I18N.format("error.version-swap", target)); } }; @@ -100,7 +102,7 @@ final class ExecutableRebrander { .map(absIcon -> { return resourceLock -> { if (iconSwap(resourceLock, absIcon.toString()) != 0) { - throw I18N.buildException().message("error.icon-swap", absIcon).create(RuntimeException::new); + throw new JPackageException(I18N.format("error.icon-swap", absIcon)); } }; }); @@ -118,43 +120,58 @@ final class ExecutableRebrander { private static void rebrandExecutable(BuildEnv env, final Path target, List actions) throws IOException { + + Objects.requireNonNull(env); + Objects.requireNonNull(target); Objects.requireNonNull(actions); actions.forEach(Objects::requireNonNull); - String tempDirectory = env.buildRoot().toAbsolutePath().toString(); - if (WindowsDefender.isThereAPotentialWindowsDefenderIssue(tempDirectory)) { - Log.verbose(I18N.format("message.potential.windows.defender.issue", tempDirectory)); - } - - var shortTargetPath = ShortPathUtils.toShortPath(target); - long resourceLock = lockResource(shortTargetPath.orElse(target).toString()); - if (resourceLock == 0) { - throw I18N.buildException().message("error.lock-resource", shortTargetPath.orElse(target)).create(RuntimeException::new); - } - - final boolean resourceUnlockedSuccess; try { - for (var action : actions) { - action.editResource(resourceLock); - } - } finally { - if (resourceLock == 0) { - resourceUnlockedSuccess = true; - } else { - resourceUnlockedSuccess = unlockResource(resourceLock); - if (shortTargetPath.isPresent()) { - // Windows will rename the executable in the unlock operation. - // Should restore executable's name. - var tmpPath = target.getParent().resolve( - target.getFileName().toString() + ".restore"); - Files.move(shortTargetPath.get(), tmpPath); - Files.move(tmpPath, target); - } - } - } + Globals.instance().objectFactory().retryExecutor(RuntimeException.class).setExecutable(() -> { - if (!resourceUnlockedSuccess) { - throw I18N.buildException().message("error.unlock-resource", target).create(RuntimeException::new); + var shortTargetPath = ShortPathUtils.toShortPath(target); + long resourceLock = lockResource(shortTargetPath.orElse(target).toString()); + if (resourceLock == 0) { + throw new JPackageException(I18N.format("error.lock-resource", shortTargetPath.orElse(target))); + } + + final boolean resourceUnlockedSuccess; + try { + for (var action : actions) { + try { + action.editResource(resourceLock); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + } finally { + if (resourceLock == 0) { + resourceUnlockedSuccess = true; + } else { + resourceUnlockedSuccess = unlockResource(resourceLock); + if (shortTargetPath.isPresent()) { + // Windows will rename the executable in the unlock operation. + // Should restore executable's name. + var tmpPath = target.getParent().resolve( + target.getFileName().toString() + ".restore"); + try { + Files.move(shortTargetPath.get(), tmpPath); + Files.move(tmpPath, target); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + } + } + + if (!resourceUnlockedSuccess) { + throw new JPackageException(I18N.format("error.unlock-resource", shortTargetPath.orElse(target))); + } + + return null; + }).setMaxAttemptsCount(5).setAttemptTimeout(3, TimeUnit.SECONDS).execute(); + } catch (UncheckedIOException ex) { + throw ex.getCause(); } } @@ -197,14 +214,13 @@ final class ExecutableRebrander { } } - private static void validateValueAndPut(Map target, - Map.Entry e, String label) { - if (e.getValue().contains("\r") || e.getValue().contains("\n")) { - Log.error("Configuration parameter " + label - + " contains multiple lines of text, ignore it"); - e = Map.entry(e.getKey(), ""); + private static String validateSingleLine(String v) { + Objects.requireNonNull(v); + if (v.contains("\r") || v.contains("\n")) { + throw new IllegalArgumentException("Configuration parameter contains multiple lines of text"); + } else { + return v; } - target.put(e.getKey(), e.getValue()); } @FunctionalInterface @@ -212,19 +228,35 @@ final class ExecutableRebrander { public void editResource(long resourceLock) throws IOException; } - private static record ExecutableProperties(String vendor, String description, + private record ExecutableProperties(String vendor, String description, DottedVersion version, String copyright, String name, String executableName) { - static ExecutableProperties create(WinApplication app, - WinLauncher launcher) { - return new ExecutableProperties(app.vendor(), launcher.description(), - app.winVersion(), app.copyright(), launcher.name(), + + ExecutableProperties { + Objects.requireNonNull(vendor); + Objects.requireNonNull(description); + Objects.requireNonNull(version); + Objects.requireNonNull(copyright); + Objects.requireNonNull(name); + Objects.requireNonNull(executableName); + } + + static ExecutableProperties create(WinApplication app, WinLauncher launcher) { + return new ExecutableProperties( + app.vendor(), + launcher.description(), + app.winVersion(), + app.copyright(), + launcher.name(), launcher.executableNameWithSuffix()); } static ExecutableProperties create(WinExePackage pkg) { - return new ExecutableProperties(pkg.app().vendor(), - pkg.description(), DottedVersion.lazy(pkg.version()), - pkg.app().copyright(), pkg.packageName(), + return new ExecutableProperties( + pkg.app().vendor(), + pkg.description(), + DottedVersion.lazy(pkg.version()), + pkg.app().copyright(), + pkg.packageName(), pkg.packageFileNameWithSuffix()); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsDefender.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsDefender.java deleted file mode 100644 index 075d87bcbca..00000000000 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsDefender.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.util.List; -import jdk.internal.util.OperatingSystem; -import jdk.internal.util.OSVersion; - -final class WindowsDefender { - - private WindowsDefender() {} - - static final boolean isThereAPotentialWindowsDefenderIssue(String dir) { - boolean result = false; - - if (OperatingSystem.isWindows() && - OSVersion.current().major() == 10) { - - // If DisableRealtimeMonitoring is not enabled then there - // may be a problem. - if (!WindowsRegistry.readDisableRealtimeMonitoring() && - !isDirectoryInExclusionPath(dir)) { - result = true; - } - } - - return result; - } - - private static boolean isDirectoryInExclusionPath(String dir) { - boolean result = false; - // If the user temp directory is not found in the exclusion - // list then there may be a problem. - List paths = WindowsRegistry.readExclusionsPaths(); - for (String s : paths) { - if (WindowsRegistry.comparePaths(s, dir)) { - result = true; - break; - } - } - - return result; - } - - static final String getUserTempDirectory() { - String tempDirectory = System.getProperty("java.io.tmpdir"); - return tempDirectory; - } -} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java deleted file mode 100644 index 7eb7b922667..00000000000 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.util.ArrayList; -import java.util.List; - -@SuppressWarnings("restricted") -final class WindowsRegistry { - - // Currently we only support HKEY_LOCAL_MACHINE. Native implementation will - // require support for additinal HKEY if needed. - private static final int HKEY_LOCAL_MACHINE = 1; - - static { - System.loadLibrary("jpackage"); - } - - private WindowsRegistry() {} - - /** - * Reads the registry value for DisableRealtimeMonitoring. - * @return true if DisableRealtimeMonitoring is set to 0x1, - * false otherwise. - */ - static final boolean readDisableRealtimeMonitoring() { - final String subKey = "Software\\Microsoft\\" - + "Windows Defender\\Real-Time Protection"; - final String value = "DisableRealtimeMonitoring"; - int result = readDwordValue(HKEY_LOCAL_MACHINE, subKey, value, 0); - return (result == 1); - } - - static final List readExclusionsPaths() { - List result = new ArrayList<>(); - final String subKey = "Software\\Microsoft\\" - + "Windows Defender\\Exclusions\\Paths"; - long lKey = openRegistryKey(HKEY_LOCAL_MACHINE, subKey); - if (lKey == 0) { - return result; - } - - String valueName; - int index = 0; - do { - valueName = enumRegistryValue(lKey, index); - if (valueName != null) { - result.add(valueName); - index++; - } - } while (valueName != null); - - closeRegistryKey(lKey); - - return result; - } - - /** - * Reads DWORD registry value. - * - * @param key one of HKEY predefine value - * @param subKey registry sub key - * @param value value to read - * @param defaultValue default value in case if subKey or value not found - * or any other errors occurred - * @return value's data only if it was read successfully, otherwise - * defaultValue - */ - private static native int readDwordValue(int key, String subKey, - String value, int defaultValue); - - /** - * Open registry key. - * - * @param key one of HKEY predefine value - * @param subKey registry sub key - * @return native handle to open key - */ - private static native long openRegistryKey(int key, String subKey); - - /** - * Enumerates the values for registry key. - * - * @param lKey native handle to open key returned by openRegistryKey - * @param index index of value starting from 0. Increment until this - * function returns NULL which means no more values. - * @return returns value or NULL if error or no more data - */ - private static native String enumRegistryValue(long lKey, int index); - - /** - * Close registry key. - * - * @param lKey native handle to open key returned by openRegistryKey - */ - private static native void closeRegistryKey(long lKey); - - /** - * Compares two Windows paths regardless case and if paths - * are short or long. - * - * @param path1 path to compare - * @param path2 path to compare - * @return true if paths point to same location - */ - public static native boolean comparePaths(String path1, String path2); -} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties index 38d0bd02bbb..13a6c989324 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties @@ -55,7 +55,6 @@ error.missing-service-installer='service-installer.exe' service installer not fo error.missing-service-installer.advice=Add 'service-installer.exe' service installer to the resource directory message.icon-not-ico=The specified icon "{0}" is not an ICO file and will not be used. The default icon will be used in it's place. -message.potential.windows.defender.issue=Warning: Windows Defender may prevent jpackage from functioning. If there is an issue, it can be addressed by either disabling realtime monitoring, or adding an exclusion for the directory "{0}". message.tool-version=Detected [{0}] version [{1}]. message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required. message.use-wix36-features=WiX {0} detected. Enabling advanced cleanup action. From a6db3f870218bc016ecc67e3f5e142d6491ac080 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 3 Mar 2026 19:11:11 +0000 Subject: [PATCH 016/655] 8378873: jpackage: remove macOS-specific code from jdk.jpackage.internal.ModuleInfo Reviewed-by: almatvee --- .../jdk/jpackage/internal/FromOptions.java | 18 +++++++++++++++++- .../jdk/jpackage/internal/ModuleInfo.java | 15 ++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java index cccd05792d6..4f590850328 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java @@ -49,6 +49,7 @@ import java.nio.file.Path; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.BiFunction; @@ -149,6 +150,13 @@ final class FromOptions { ApplicationLayout appLayout, RuntimeLayout runtimeLayout, Optional predefinedRuntimeLayout) { + Objects.requireNonNull(options); + Objects.requireNonNull(launcherCtor); + Objects.requireNonNull(launcherOverrideCtor); + Objects.requireNonNull(appLayout); + Objects.requireNonNull(runtimeLayout); + Objects.requireNonNull(predefinedRuntimeLayout); + final var appBuilder = new ApplicationBuilder(); final var isRuntimeInstaller = isRuntimeInstaller(options); @@ -185,7 +193,15 @@ final class FromOptions { } else { appBuilder.appImageLayout(appLayout); - final var launchers = createLaunchers(options, launcherCtor); + // Adjust the value of the PREDEFINED_RUNTIME_IMAGE option to make it reference + // a directory with the standard Java runtime structure. + final var launcherOptions = predefinedRuntimeDirectory.filter(v -> { + return !predefinedRuntimeImage.get().equals(v); + }).map(v -> { + return Options.of(Map.of(PREDEFINED_RUNTIME_IMAGE, v)).copyWithParent(options); + }).orElse(options); + + final var launchers = createLaunchers(launcherOptions, launcherCtor); if (PREDEFINED_APP_IMAGE.containsIn(options)) { appBuilder.launchers(launchers); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ModuleInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ModuleInfo.java index 590321d5e86..71d1a66659e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ModuleInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ModuleInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Properties; -import jdk.internal.util.OperatingSystem; record ModuleInfo(String name, Optional version, Optional mainClass, Optional location) { @@ -61,17 +60,7 @@ record ModuleInfo(String name, Optional version, Optional mainCl // is linked in the runtime by simply analysing the data // of `release` file. - final Path releaseFile; - if (!OperatingSystem.isMacOS()) { - releaseFile = cookedRuntime.resolve("release"); - } else { - // On Mac `cookedRuntime` can be runtime root or runtime home. - Path runtimeHome = cookedRuntime.resolve("Contents/Home"); - if (!Files.isDirectory(runtimeHome)) { - runtimeHome = cookedRuntime; - } - releaseFile = runtimeHome.resolve("release"); - } + final Path releaseFile = cookedRuntime.resolve("release"); try (Reader reader = Files.newBufferedReader(releaseFile)) { Properties props = new Properties(); From 73363a0cb501eb10f5be4a6a283b20da58b1950d Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 3 Mar 2026 21:53:20 +0000 Subject: [PATCH 017/655] 8378874: jpackage: remove redundant messages Reviewed-by: almatvee --- .../jdk/jpackage/internal/MacPkgPackager.java | 6 ------ .../internal/resources/MacResources.properties | 1 - .../jdk/jpackage/internal/WinMsiPackager.java | 3 --- .../internal/WixAppImageFragmentBuilder.java | 13 +------------ .../jdk/jpackage/internal/WixFragmentBuilder.java | 9 ++------- .../internal/resources/WinResources.properties | 1 - 6 files changed, 3 insertions(+), 30 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index fc5c85c699c..369ab201611 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -51,7 +51,6 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import jdk.internal.util.Architecture; -import jdk.internal.util.OSVersion; import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacPkgPackage; @@ -509,11 +508,6 @@ record MacPkgPackager(BuildEnv env, MacPkgPackage pkg, Optional servic // maybe sign if (pkg.sign()) { - if (OSVersion.current().compareTo(new OSVersion(10, 12)) >= 0) { - // we need this for OS X 10.12+ - Log.verbose(I18N.getString("message.signing.pkg")); - } - final var pkgSigningConfig = pkg.signingConfig().orElseThrow(); commandLine.add("--sign"); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index 3aebdc39d41..90c4162b80e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -61,7 +61,6 @@ message.invalid-identifier.advice=specify identifier with "--mac-package-identif message.preparing-dmg-setup=Preparing dmg setup: {0}. message.preparing-scripts=Preparing package scripts. message.preparing-distribution-dist=Preparing distribution.dist: {0}. -message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trust" for your certificate using "Keychain Access" tool. message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue. message.codesign.failed.reason.app.content="codesign" failed and additional application content was supplied via the "--app-content" parameter. Probably the additional content broke the integrity of the application bundle and caused the failure. Ensure content supplied via the "--app-content" parameter does not break the integrity of the application bundle, or add it in the post-processing step. message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem. diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java index c72b14a76d5..a53d083847a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java @@ -151,9 +151,6 @@ final class WinMsiPackager implements Consumer { wixFragments.forEach(wixFragment -> wixFragment.setWixVersion(wixToolset.getVersion(), wixToolset.getType())); - - wixFragments.stream().map(WixFragmentBuilder::getLoggableWixFeatures).flatMap( - List::stream).distinct().toList().forEach(Log::verbose); } WinMsiPackager(BuildEnv env, WinMsiPackage pkg, Path outputDir, WinSystemEnvironment sysEnv) { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java index 0dff5c26ae2..ac7af873739 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import static jdk.jpackage.internal.util.CollectionUtils.toCollection; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -142,16 +141,6 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder { super.addFilesToConfigRoot(); } - @Override - List getLoggableWixFeatures() { - if (isWithWix36Features()) { - return List.of(MessageFormat.format(I18N.getString("message.use-wix36-features"), - getWixVersion())); - } else { - return List.of(); - } - } - @Override protected Collection getFragmentWriters() { return List.of( diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java index 4d180a94871..46894699d98 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixFragmentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,19 +30,18 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.nio.file.Path; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.xml.stream.XMLStreamWriter; -import jdk.jpackage.internal.util.XmlConsumer; import jdk.internal.util.Architecture; import jdk.jpackage.internal.WixSourceConverter.ResourceGroup; import jdk.jpackage.internal.WixToolset.WixToolsetType; import jdk.jpackage.internal.model.DottedVersion; import jdk.jpackage.internal.model.WinMsiPackage; +import jdk.jpackage.internal.util.XmlConsumer; import jdk.jpackage.internal.util.XmlUtils; /** @@ -72,10 +71,6 @@ abstract class WixFragmentBuilder { fragmentResource = env.createResource(defaultResourceName).setPublicName(outputFileName); } - List getLoggableWixFeatures() { - return List.of(); - } - void configureWixPipeline(WixPipeline.Builder wixPipeline) { wixPipeline.addSource(configRoot.resolve(outputFileName), Optional.ofNullable(wixVariables).map(WixVariables::getValues).orElse( diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties index 13a6c989324..0f3dcab8260 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties @@ -57,7 +57,6 @@ error.missing-service-installer.advice=Add 'service-installer.exe' service insta message.icon-not-ico=The specified icon "{0}" is not an ICO file and will not be used. The default icon will be used in it's place. message.tool-version=Detected [{0}] version [{1}]. message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required. -message.use-wix36-features=WiX {0} detected. Enabling advanced cleanup action. message.product-code=MSI ProductCode: {0}. message.upgrade-code=MSI UpgradeCode: {0}. message.preparing-msi-config=Preparing MSI config: {0}. From 0729d1d82207de856fdd8d2fe2a2ea4a0b8694a2 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Wed, 4 Mar 2026 00:36:08 +0000 Subject: [PATCH 018/655] 8379039: Build failure on vector API source generation after JDK-8378312 Reviewed-by: jbhateja, psandoz --- .../share/classes/jdk/incubator/vector/X-Vector.java.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index d6763c2c03a..95fe8ca35db 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -772,7 +772,7 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { @ForceInline final $abstractvectortype$ unaryMathOp(VectorOperators.Unary op) { - return VectorMathLibrary.unaryMathOp(op, opCode(op), species(), $abstractvectortype$::unaryOperations, + return VectorMathLibrary.unaryMathOp(op, opCode(op), vspecies(), $abstractvectortype$::unaryOperations, this); } #end[FP] @@ -983,7 +983,7 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { @ForceInline final $abstractvectortype$ binaryMathOp(VectorOperators.Binary op, $abstractvectortype$ that) { - return VectorMathLibrary.binaryMathOp(op, opCode(op), species(), $abstractvectortype$::binaryOperations, + return VectorMathLibrary.binaryMathOp(op, opCode(op), vspecies(), $abstractvectortype$::binaryOperations, this, that); } #end[FP] From 284d1310d059764b5fb887d4693af623c2f7e89a Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 4 Mar 2026 00:49:05 +0000 Subject: [PATCH 019/655] 8378876: jpackage: facilitate testing with mocks Reviewed-by: almatvee --- .../jpackage/internal/LibProvidersLookup.java | 2 +- .../LinuxDebSystemEnvironmentMixin.java | 3 ++ .../LinuxRpmSystemEnvironmentMixin.java | 4 +- .../internal/MacBundlingEnvironment.java | 5 +++ .../internal/MacDmgSystemEnvironment.java | 23 ++++++++--- .../jdk/jpackage/internal/AppImageFile.java | 13 ------- .../internal/DefaultBundlingEnvironment.java | 9 +++++ .../jpackage/internal/OptionsTransformer.java | 7 +++- .../jdk/jpackage/internal/PackageBuilder.java | 22 ++++++----- .../jdk/jpackage/internal/ToolValidator.java | 4 -- .../jdk/jpackage/internal/cli/Main.java | 39 +++++++++++-------- .../internal/cli/OptionsAnalyzer.java | 12 +++--- .../internal/cli/OptionsProcessor.java | 6 ++- .../jpackage/internal/cli/StandardOption.java | 6 +++ .../jdk/jpackage/test/AppImageFile.java | 16 ++++---- .../helpers/jdk/jpackage/test/JavaTool.java | 5 ++- .../helpers/jdk/jpackage/test/TKit.java | 39 +++++++++++++++---- .../test/stdmock/JPackageMockUtils.java | 2 +- .../jpackage/internal/AppImageFileTest.java | 16 +++++--- .../jdk/jpackage/internal/cli/MainTest.java | 6 ++- .../internal/cli/OptionsProcessorTest.java | 4 +- .../cli/OptionsValidationFailTest.java | 2 +- 22 files changed, 157 insertions(+), 88 deletions(-) diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LibProvidersLookup.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LibProvidersLookup.java index 6faacbca528..2dccc91cf8f 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LibProvidersLookup.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LibProvidersLookup.java @@ -44,7 +44,7 @@ import java.util.stream.Stream; */ public final class LibProvidersLookup { static boolean supported() { - return (new ToolValidator(TOOL_LDD).validate() == null); + return (new ToolValidator(TOOL_LDD).setCommandLine("--version").validate() == null); } LibProvidersLookup setPackageLookup(PackageLookup v) { diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java index 2cf3e9e36e8..4c6fd75bed8 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java @@ -40,6 +40,9 @@ interface LinuxDebSystemEnvironmentMixin { static Result create() { final var errors = Stream.of(Internal.TOOL_DPKG_DEB, Internal.TOOL_DPKG, Internal.TOOL_FAKEROOT) .map(ToolValidator::new) + .map(v -> { + return v.setCommandLine("--version"); + }) .map(ToolValidator::validate) .filter(Objects::nonNull) .toList(); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java index 4cbd3ce4a9c..8de28b79430 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java @@ -44,7 +44,9 @@ interface LinuxRpmSystemEnvironmentMixin { final var errors = Stream.of( Internal.createRpmbuildToolValidator(), new ToolValidator(Internal.TOOL_RPM) - ).map(ToolValidator::validate).filter(Objects::nonNull).toList(); + ).map(v -> { + return v.setCommandLine("--version"); + }).map(ToolValidator::validate).filter(Objects::nonNull).toList(); if (errors.isEmpty()) { return Result.ofValue(new Stub(Internal.TOOL_RPM, Internal.TOOL_RPMBUILD)); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java index 224ea20f249..1e60d8490f0 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBundlingEnvironment.java @@ -31,6 +31,7 @@ import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_APP import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_DMG; import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_PKG; import static jdk.jpackage.internal.cli.StandardBundlingOperation.SIGN_MAC_APP_IMAGE; +import static jdk.jpackage.internal.cli.StandardOption.EXIT_AFTER_CONFIGURATION_PHASE; import java.util.Optional; import jdk.jpackage.internal.cli.Options; @@ -74,6 +75,10 @@ public class MacBundlingEnvironment extends DefaultBundlingEnvironment { final var pkg = createSignAppImagePackage(app, env); + if (EXIT_AFTER_CONFIGURATION_PHASE.getFrom(options)) { + return; + } + buildPipeline(pkg).create().execute(env, pkg, env.appImageDir()); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java index 12d105b99b5..11cf94ca66d 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java @@ -31,6 +31,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.util.Result; record MacDmgSystemEnvironment(Path hdiutil, Path osascript, Optional setFileUtility) implements SystemEnvironment { @@ -39,12 +40,22 @@ record MacDmgSystemEnvironment(Path hdiutil, Path osascript, Optional setF } static Result create() { - final var errors = Stream.of(HDIUTIL, OSASCRIPT) - .map(ToolValidator::new) - .map(ToolValidator::checkExistsOnly) - .map(ToolValidator::validate) - .filter(Objects::nonNull) - .toList(); + + List errors; + + if (OperatingSystem.isMacOS()) { + errors = Stream.of(HDIUTIL, OSASCRIPT) + .map(ToolValidator::new) + .map(ToolValidator::checkExistsOnly) + .map(ToolValidator::validate) + .filter(Objects::nonNull) + .toList(); + } else { + // The code runs on an OS other than macOS. Presume this is mock testing. + // Don't validate the tools; checking that their executables exist will fail in this environment. + errors = List.of(); + } + if (errors.isEmpty()) { return Result.ofValue(new MacDmgSystemEnvironment(HDIUTIL, OSASCRIPT, findSetFileUtility())); } else { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 75ead9d08ad..7edc6cd3c11 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -134,19 +134,6 @@ final class AppImageFile { return appLayout.appDirectory().resolve(FILENAME); } - /** - * Loads application image info from the specified application layout. - *

- * It is an equivalent to calling - * {@link #load(ApplicationLayout, OperatingSystem)} method with - * {@code OperatingSystem.current()} for the second parameter. - * - * @param appLayout the application layout - */ - static ExternalApplication load(ApplicationLayout appLayout) { - return load(appLayout, OperatingSystem.current()); - } - /** * Loads application image info from the specified application layout and OS. * diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java index fc51f60aa66..ae4b1005318 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DefaultBundlingEnvironment.java @@ -25,6 +25,7 @@ package jdk.jpackage.internal; import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.internal.cli.StandardOption.EXIT_AFTER_CONFIGURATION_PHASE; import static jdk.jpackage.internal.util.MemoizingSupplier.runOnce; import java.io.IOException; @@ -129,6 +130,10 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { Objects.requireNonNull(app); Objects.requireNonNull(pipelineBuilder); + if (EXIT_AFTER_CONFIGURATION_PHASE.getFrom(options)) { + return; + } + final var outputDir = PathUtils.normalizedAbsolutePath(OptionUtils.outputDir(options).resolve(app.appImageDirName())); Log.verbose(I18N.getString("message.create-app-image")); @@ -170,6 +175,10 @@ class DefaultBundlingEnvironment implements CliBundlingEnvironment { Objects.requireNonNull(createPipelineBuilder); Objects.requireNonNull(pipelineBuilderMutatorFactory); + if (EXIT_AFTER_CONFIGURATION_PHASE.getFrom(options)) { + return; + } + var pipelineBuilder = Objects.requireNonNull(createPipelineBuilder.apply(pkg)); // Delete an old output package file (if any) before creating a new one. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionsTransformer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionsTransformer.java index a01be089a49..f7b535b06f6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionsTransformer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/OptionsTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,10 @@ record OptionsTransformer(Options mainOptions, Optional ext } OptionsTransformer(Options mainOptions, ApplicationLayout appLayout) { - this(mainOptions, PREDEFINED_APP_IMAGE.findIn(mainOptions).map(appLayout::resolveAt).map(AppImageFile::load)); + this(mainOptions, PREDEFINED_APP_IMAGE.findIn(mainOptions).map(appLayout::resolveAt).map(resolvedLayout -> { + var os = OptionUtils.bundlingOperation(mainOptions).os(); + return AppImageFile.load(resolvedLayout, os); + })); } Options appOptions() { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java index f537a1ea0a2..8b61ef19fa2 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -207,7 +207,7 @@ final class PackageBuilder { }); } - private static Path mapInstallDir(Path installDir, PackageType pkgType) { + private static Path mapInstallDir(Path installDir, PackageType type) { var ex = buildConfigException("error.invalid-install-dir", installDir).create(); if (installDir.getNameCount() == 0) { @@ -223,15 +223,17 @@ final class PackageBuilder { throw ex; } - switch (pkgType) { - case StandardPackageType.WIN_EXE, StandardPackageType.WIN_MSI -> { - if (installDir.isAbsolute()) { - throw ex; + if (type instanceof StandardPackageType stdType) { + switch (stdType) { + case WIN_EXE, WIN_MSI -> { + if (installDir.isAbsolute()) { + throw ex; + } } - } - default -> { - if (!installDir.isAbsolute()) { - throw ex; + default -> { + if (!installDir.isAbsolute()) { + throw ex; + } } } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java index 9440aff3a53..13a9e05e934 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java @@ -33,7 +33,6 @@ import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; -import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.DottedVersion; @@ -46,9 +45,6 @@ final class ToolValidator { ToolValidator(Path toolPath) { this.toolPath = Objects.requireNonNull(toolPath); - if (OperatingSystem.isLinux()) { - setCommandLine("--version"); - } } ToolValidator setCommandLine(String... args) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java index d40895a7da6..5789203c3e9 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/Main.java @@ -64,14 +64,15 @@ import jdk.jpackage.internal.util.function.ExceptionBox; */ public final class Main { - public record Provider(Supplier bundlingEnvSupplier) implements ToolProvider { + public record Provider(Supplier bundlingEnvSupplier, OperatingSystem os) implements ToolProvider { public Provider { Objects.requireNonNull(bundlingEnvSupplier); + Objects.requireNonNull(os); } public Provider() { - this(DefaultBundlingEnvironmentLoader.INSTANCE); + this(DefaultBundlingEnvironmentLoader.INSTANCE, OperatingSystem.current()); } @Override @@ -81,7 +82,7 @@ public final class Main { @Override public int run(PrintWriter out, PrintWriter err, String... args) { - return Main.run(bundlingEnvSupplier, out, err, args); + return Main.run(os, bundlingEnvSupplier, out, err, args); } @Override @@ -107,25 +108,29 @@ public final class Main { public static void main(String... args) { var out = toPrintWriter(System.out); var err = toPrintWriter(System.err); - System.exit(run(out, err, args)); + System.exit(run(OperatingSystem.current(), DefaultBundlingEnvironmentLoader.INSTANCE, out, err, args)); } - static int run(PrintWriter out, PrintWriter err, String... args) { - return run(DefaultBundlingEnvironmentLoader.INSTANCE, out, err, args); - } - - static int run(Supplier bundlingEnvSupplier, PrintWriter out, PrintWriter err, String... args) { - return Globals.main(() -> { - return runWithGlobals(bundlingEnvSupplier, out, err, args); - }); - } - - private static int runWithGlobals( + static int run( + OperatingSystem os, Supplier bundlingEnvSupplier, PrintWriter out, PrintWriter err, String... args) { + return Globals.main(() -> { + return runWithGlobals(os, bundlingEnvSupplier, out, err, args); + }); + } + + private static int runWithGlobals( + OperatingSystem os, + Supplier bundlingEnvSupplier, + PrintWriter out, + PrintWriter err, + String... args) { + + Objects.requireNonNull(os); Objects.requireNonNull(bundlingEnvSupplier); Objects.requireNonNull(args); for (String arg : args) { @@ -162,7 +167,7 @@ public final class Main { final var bundlingEnv = bundlingEnvSupplier.get(); - final var parseResult = Utils.buildParser(OperatingSystem.current(), bundlingEnv).create().apply(mappedArgs.get()); + final var parseResult = Utils.buildParser(os, bundlingEnv).create().apply(mappedArgs.get()); return runner.run(() -> { final var parsedOptionsBuilder = parseResult.orElseThrow(); @@ -189,7 +194,7 @@ public final class Main { Globals.instance().loggerVerbose(); } - final var optionsProcessor = new OptionsProcessor(parsedOptionsBuilder, bundlingEnv); + final var optionsProcessor = new OptionsProcessor(parsedOptionsBuilder, os, bundlingEnv); final var validationResult = optionsProcessor.validate(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java index 6c32a3d1569..fb1dd20df92 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsAnalyzer.java @@ -63,8 +63,8 @@ import jdk.jpackage.internal.model.BundleType; */ final class OptionsAnalyzer { - OptionsAnalyzer(Options cmdline, BundlingEnvironment bundlingEnv) { - this(cmdline, getBundlingOperation(cmdline, OperatingSystem.current(), bundlingEnv), false); + OptionsAnalyzer(Options cmdline, OperatingSystem os, BundlingEnvironment bundlingEnv) { + this(cmdline, getBundlingOperation(cmdline, os, bundlingEnv), false); } OptionsAnalyzer(Options cmdline, StandardBundlingOperation bundlingOperation) { @@ -291,17 +291,17 @@ final class OptionsAnalyzer { return bundlingOperations.getFirst(); } else { // Multiple standard bundling operations produce the `bundleType` bundle type. - // Filter those that belong to the current OS + // Filter those that belong to the specified OS. bundlingOperations = bundlingOperations.stream().filter(op -> { - return op.os().equals(OperatingSystem.current()); + return op.os().equals(os); }).toList(); if (bundlingOperations.isEmpty()) { // jpackage internal error: none of the standard bundling operations produce - // bundles of the `bundleType` on the current OS. + // bundles of the `bundleType` on the specified OS. throw new AssertionError(String.format( "None of the standard bundling operations produce bundles of type [%s] on %s", - bundleType, OperatingSystem.current())); + bundleType, os)); } else if (bundlingOperations.size() == 1) { return bundlingOperations.getFirst(); } else if (StandardBundlingOperation.MACOS_APP_IMAGE.containsAll(bundlingOperations)) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java index 3c0eab77f8a..387c36ea416 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/OptionsProcessor.java @@ -62,8 +62,9 @@ import jdk.jpackage.internal.util.Result; */ final class OptionsProcessor { - OptionsProcessor(OptionsBuilder optionsBuilder, CliBundlingEnvironment bundlingEnv) { + OptionsProcessor(OptionsBuilder optionsBuilder, OperatingSystem os, CliBundlingEnvironment bundlingEnv) { this.optionsBuilder = Objects.requireNonNull(optionsBuilder); + this.os = Objects.requireNonNull(os); this.bundlingEnv = Objects.requireNonNull(bundlingEnv); } @@ -88,7 +89,7 @@ final class OptionsProcessor { final var untypedOptions = optionsBuilder.create(); // Create command line structure analyzer. - final var analyzerResult = Result.of(() -> new OptionsAnalyzer(untypedOptions, bundlingEnv)); + final var analyzerResult = Result.of(() -> new OptionsAnalyzer(untypedOptions, os, bundlingEnv)); if (analyzerResult.hasErrors()) { // Failed to derive the bundling operation from the command line. allErrors.addAll(analyzerResult.mapErrors().errors()); @@ -419,6 +420,7 @@ final class OptionsProcessor { private final JOptSimpleOptionsBuilder.OptionsBuilder optionsBuilder; + private final OperatingSystem os; private final CliBundlingEnvironment bundlingEnv; private static final OptionValue> ADD_LAUNCHER_INTERNAL = diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index eca82da99aa..f554fc12ec6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -434,6 +434,12 @@ public final class StandardOption { public static final OptionValue BUNDLING_OPERATION_DESCRIPTOR = OptionValue.create(); + /** + * Debug option telling bundler to exit after the configuration phase is over, + * without running the packaging phase. + */ + public static final OptionValue EXIT_AFTER_CONFIGURATION_PHASE = OptionValue.build().defaultValue(false).create(); + /** * Returns options configuring a launcher. * diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java index 55b13a06620..2dcccc673a9 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AppImageFile.java @@ -41,7 +41,6 @@ import javax.xml.stream.XMLStreamWriter; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -195,13 +194,16 @@ public record AppImageFile(String mainLauncherName, Optional mainLaunche } private static String getPlatform() { - return PLATFORM_LABELS.get(OperatingSystem.current()); + if (TKit.isLinux()) { + return "linux"; + } else if (TKit.isWindows()) { + return "windows"; + } else if (TKit.isOSX()) { + return "macOS"; + } else { + throw new IllegalStateException(); + } } private static final String FILENAME = ".jpackage.xml"; - - private static final Map PLATFORM_LABELS = Map.of( - OperatingSystem.LINUX, "linux", - OperatingSystem.WINDOWS, "windows", - OperatingSystem.MACOS, "macOS"); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java index 0bbf71fe0cd..4ca4b918355 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ package jdk.jpackage.test; import java.nio.file.Path; import java.util.spi.ToolProvider; +import jdk.internal.util.OperatingSystem; public enum JavaTool { JAVA, JAVAC, JPACKAGE, JAR, JLINK, JMOD, JSHELL; @@ -50,7 +51,7 @@ public enum JavaTool { private Path relativePathInJavaHome() { Path path = Path.of("bin", toolName()); - if (TKit.isWindows()) { + if (OperatingSystem.isWindows()) { path = path.getParent().resolve(path.getFileName().toString() + ".exe"); } return path; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 88d11d75f45..db76309c292 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -77,6 +77,9 @@ import jdk.jpackage.internal.util.function.ThrowingUnaryOperator; public final class TKit { + private static final ScopedValue STATE = ScopedValue.newInstance(); + private static final State DEFAULT_STATE = State.build().initDefaults().mutable(false).create(); + public static final Path TEST_SRC_ROOT = Functional.identity(() -> { Path root = Path.of(System.getProperty("test.src")); @@ -128,6 +131,15 @@ public final class TKit { } } + public static void withOperatingSystem(ThrowingRunnable action, OperatingSystem os) { + Objects.requireNonNull(action); + Objects.requireNonNull(os); + + withState(action, stateBuilder -> { + stateBuilder.os(os); + }); + } + public static void withState(ThrowingRunnable action, Consumer stateBuilderMutator) { Objects.requireNonNull(action); Objects.requireNonNull(stateBuilderMutator); @@ -233,21 +245,25 @@ public final class TKit { } public static boolean isWindows() { - return OperatingSystem.isWindows(); + return TKit.state().os == OperatingSystem.WINDOWS; } public static boolean isOSX() { - return OperatingSystem.isMacOS(); + return TKit.state().os == OperatingSystem.MACOS; } public static boolean isLinux() { - return OperatingSystem.isLinux(); + return TKit.state().os == OperatingSystem.LINUX; } public static boolean isLinuxAPT() { return isLinux() && Files.exists(Path.of("/usr/bin/apt-get")); } + public static boolean isMockingOperatingSystem() { + return TKit.state().os != OperatingSystem.current(); + } + private static String addTimestamp(String msg) { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); Date time = new Date(System.currentTimeMillis()); @@ -1314,6 +1330,7 @@ public final class TKit { public static final class State { private State( + OperatingSystem os, TestInstance currentTest, PrintStream out, PrintStream err, @@ -1323,10 +1340,12 @@ public final class TKit { boolean verboseJPackage, boolean verboseTestSetup) { + Objects.requireNonNull(os); Objects.requireNonNull(out); Objects.requireNonNull(err); Objects.requireNonNull(properties); + this.os = os; this.currentTest = currentTest; this.out = out; this.err = err; @@ -1371,6 +1390,7 @@ public final class TKit { static final class Builder { Builder initDefaults() { + os = null; currentTest = null; out = System.out; err = System.err; @@ -1403,6 +1423,7 @@ public final class TKit { } Builder initFrom(State state) { + os = state.os; currentTest = state.currentTest; out = state.out; err = state.err; @@ -1418,6 +1439,11 @@ public final class TKit { return this; } + Builder os(OperatingSystem v) { + os = v; + return this; + } + Builder currentTest(TestInstance v) { currentTest = v; return this; @@ -1449,6 +1475,7 @@ public final class TKit { State create() { return new State( + Optional.ofNullable(os).orElseGet(OperatingSystem::current), currentTest, out, err, @@ -1459,6 +1486,7 @@ public final class TKit { verboseTestSetup); } + private OperatingSystem os; private TestInstance currentTest; private PrintStream out; private PrintStream err; @@ -1474,6 +1502,7 @@ public final class TKit { } + private OperatingSystem os; private final TestInstance currentTest; private final PrintStream out; private final PrintStream err; @@ -1486,8 +1515,4 @@ public final class TKit { private final boolean verboseJPackage; private final boolean verboseTestSetup; } - - - private static final ScopedValue STATE = ScopedValue.newInstance(); - private static final State DEFAULT_STATE = State.build().initDefaults().mutable(false).create(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/JPackageMockUtils.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/JPackageMockUtils.java index 604bcd0711f..085102390ff 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/JPackageMockUtils.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/JPackageMockUtils.java @@ -213,7 +213,7 @@ public final class JPackageMockUtils { var impl = new Main.Provider(runOnce(() -> { return createBundlingEnvironment(os); - })); + }), os); return new ToolProvider() { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 8fdcc96acff..85b15d77052 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -108,7 +108,9 @@ public class AppImageFileTest { @Test public void testNoSuchFile() throws IOException { - var ex = assertThrowsExactly(JPackageException.class, () -> AppImageFile.load(DUMMY_LAYOUT.resolveAt(tempFolder))); + var ex = assertThrowsExactly(JPackageException.class, () -> { + AppImageFile.load(DUMMY_LAYOUT.resolveAt(tempFolder), OperatingSystem.current()); + }); Assertions.assertEquals(I18N.format("error.missing-app-image-file", ".jpackage.xml", tempFolder), ex.getMessage()); assertNull(ex.getCause()); } @@ -117,7 +119,9 @@ public class AppImageFileTest { public void testDirectory() throws IOException { Files.createDirectory(AppImageFile.getPathInAppImage(DUMMY_LAYOUT.resolveAt(tempFolder))); - var ex = assertThrowsExactly(JPackageException.class, () -> AppImageFile.load(DUMMY_LAYOUT.resolveAt(tempFolder))); + var ex = assertThrowsExactly(JPackageException.class, () -> { + AppImageFile.load(DUMMY_LAYOUT.resolveAt(tempFolder), OperatingSystem.current()); + }); Assertions.assertEquals(I18N.format("error.reading-app-image-file", ".jpackage.xml", tempFolder), ex.getMessage()); assertNotNull(ex.getCause()); } @@ -131,7 +135,9 @@ public class AppImageFileTest { Files.writeString(appImageFile, ""); try (var out = new FileOutputStream(appImageFile.toFile()); var lock = out.getChannel().lock()) { - var ex = assertThrowsExactly(JPackageException.class, () -> AppImageFile.load(DUMMY_LAYOUT.resolveAt(tempFolder))); + var ex = assertThrowsExactly(JPackageException.class, () -> { + AppImageFile.load(DUMMY_LAYOUT.resolveAt(tempFolder), OperatingSystem.current()); + }); Assertions.assertEquals(I18N.format("error.reading-app-image-file", ".jpackage.xml", tempFolder), ex.getMessage()); assertNotNull(ex.getCause()); } @@ -237,7 +243,7 @@ public class AppImageFileTest { final var copy = toSupplier(() -> { var layout = DUMMY_LAYOUT.resolveAt(dir); new AppImageFile(app).save(layout); - return AppImageFile.load(layout); + return AppImageFile.load(layout, OperatingSystem.current()); }).get(); assertEquals(createExternalApplication(OperatingSystem.current()), copy); @@ -638,7 +644,7 @@ public class AppImageFileTest { private static final ApplicationLayout DUMMY_LAYOUT = ApplicationLayout.build().setAll("").create(); - private final static Map OPTIONS = Stream.of(AppImageFileOptionScope.values()) + private static final Map OPTIONS = Stream.of(AppImageFileOptionScope.values()) .flatMap(AppImageFileOptionScope::options) .collect(toMap(OptionValue::id, OptionValue::getName)); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java index 1c06d592006..3f933093e97 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java @@ -461,7 +461,11 @@ public class MainTest extends JUnitAdapter { var stdout = new StringWriter(); var stderr = new StringWriter(); - var exitCode = Main.run(new PrintWriter(stdout), new PrintWriter(stderr), args); + var os = OperatingSystem.current(); + var exitCode = Main.run(os, () -> { + CliBundlingEnvironment bundlingEnv = JPackageMockUtils.createBundlingEnvironment(os); + return bundlingEnv; + }, new PrintWriter(stdout), new PrintWriter(stderr), args); return new ExecutionResult(lines(stdout.toString()), lines(stderr.toString()), exitCode); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsProcessorTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsProcessorTest.java index 53b726d8f1a..499aab2f24a 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsProcessorTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsProcessorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -664,7 +664,7 @@ public class OptionsProcessorTest { var optionsBuilder = Utils.buildParser(os, bundlingEnv).create().apply(stringArgs).orElseThrow(); - var op = new OptionsProcessor(optionsBuilder, bundlingEnv); + var op = new OptionsProcessor(optionsBuilder, OperatingSystem.current(), bundlingEnv); Collection> errors; if (expectedValidationErrorsOrdered) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java index 9976a71ef3f..3381677cb61 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.java @@ -105,7 +105,7 @@ public class OptionsValidationFailTest { final var firstErr = errors.stream().findFirst().orElseThrow(); errorReporter.reportError(firstErr); }).map(builder -> { - var result = new OptionsProcessor(builder, bundlingEnv).validate(); + var result = new OptionsProcessor(builder, OperatingSystem.current(), bundlingEnv).validate(); if (result.hasValue()) { return 0; } else { From 7f518deb2c6ac54867a266ce16023183e7ced053 Mon Sep 17 00:00:00 2001 From: Frederic Thevenet Date: Wed, 4 Mar 2026 05:48:30 +0000 Subject: [PATCH 020/655] 8378584: (process) Investigate and fix Alpine errors in Basic.java ProcessBuilder test, and re-enable tests Reviewed-by: stuefe --- test/jdk/java/lang/ProcessBuilder/Basic.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index 7034174f85c..dd97de8fad8 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ * @summary Basic tests for Process and Environment Variable code * @modules java.base/java.lang:open * java.base/java.io:open - * @requires !vm.musl * @requires vm.flagless * @library /test/lib * @run main/othervm/native/timeout=360 Basic @@ -46,7 +45,7 @@ * @modules java.base/java.lang:open * java.base/java.io:open * java.base/jdk.internal.misc - * @requires (os.family == "linux" & !vm.musl) + * @requires (os.family == "linux") * @library /test/lib * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=posix_spawn Basic */ From d9e256d3b2bb96ab079ccab51a5d3b32900aa632 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 4 Mar 2026 06:11:02 +0000 Subject: [PATCH 021/655] 8372245: GTest globalDefinitions.format_specifiers cannot run without VM Reviewed-by: kbarrett, iwalulya --- test/hotspot/gtest/utilities/test_globalDefinitions.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/hotspot/gtest/utilities/test_globalDefinitions.cpp b/test/hotspot/gtest/utilities/test_globalDefinitions.cpp index 6636efbba8e..b8b65ae8ca8 100644 --- a/test/hotspot/gtest/utilities/test_globalDefinitions.cpp +++ b/test/hotspot/gtest/utilities/test_globalDefinitions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,6 @@ */ #include "cppstdlib/type_traits.hpp" -#include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" @@ -220,10 +219,9 @@ TEST(globalDefinitions, array_size) { #define check_format(format, value, expected) \ do { \ - ResourceMark rm; \ stringStream out; \ out.print((format), (value)); \ - const char* result = out.as_string(); \ + const char* result = out.base(); \ EXPECT_STREQ((result), (expected)) << "Failed with" \ << " format '" << (format) << "'" \ << " value '" << (value); \ From 3cd0b99990ae50579e6f99c043beb1ab3f2f5e89 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 4 Mar 2026 06:13:05 +0000 Subject: [PATCH 022/655] 8372248: GTest istream.coverage depends on istream.basic Reviewed-by: kbarrett, iwalulya --- test/hotspot/gtest/utilities/test_istream.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/hotspot/gtest/utilities/test_istream.cpp b/test/hotspot/gtest/utilities/test_istream.cpp index c07450822af..643d8cf8fcf 100644 --- a/test/hotspot/gtest/utilities/test_istream.cpp +++ b/test/hotspot/gtest/utilities/test_istream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -305,16 +305,13 @@ static void istream_test_driver(const bool VERBOSE, } TEST_VM(istream, basic) { - const bool VERBOSE = false; - istream_test_driver(VERBOSE, false, false, false); -} - -TEST_VM(istream, coverage) { - const bool VERBOSE = false; + const bool VERBOSE_TEST = false; + const bool VERBOSE_COVERAGE = false; + istream_test_driver(VERBOSE_TEST, false, false, false); #ifdef ASSERT istream_coverage_mode(0, cases, total, zeroes); if (cases == 0) return; - if (VERBOSE || zeroes != 0) + if (VERBOSE_COVERAGE || zeroes != 0) istream_coverage_mode(-1, cases, total, zeroes); EXPECT_EQ(zeroes, 0) << "zeroes: " << zeroes << "/" << cases; #endif //ASSERT From 39b1e9d839c0f0089565c55accdcab5337839fbf Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 4 Mar 2026 07:07:00 +0000 Subject: [PATCH 023/655] 8372247: OSX: Semaphore.trywait requires os::Bsd::clock_init Reviewed-by: dholmes, kbarrett --- src/hotspot/os/bsd/semaphore_bsd.cpp | 44 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/hotspot/os/bsd/semaphore_bsd.cpp b/src/hotspot/os/bsd/semaphore_bsd.cpp index 827c955677e..c35712ff2da 100644 --- a/src/hotspot/os/bsd/semaphore_bsd.cpp +++ b/src/hotspot/os/bsd/semaphore_bsd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,27 +81,37 @@ bool OSXSemaphore::timedwait(int64_t millis) { // kernel semaphores take a relative timeout mach_timespec_t waitspec; - int secs = millis / MILLIUNITS; - int nsecs = millis_to_nanos(millis % MILLIUNITS); - waitspec.tv_sec = secs; - waitspec.tv_nsec = nsecs; + int64_t starttime; + const bool is_trywait = millis == 0; - int64_t starttime = os::javaTimeNanos(); + if (!is_trywait) { + int secs = millis / MILLIUNITS; + int nsecs = millis_to_nanos(millis % MILLIUNITS); + waitspec.tv_sec = secs; + waitspec.tv_nsec = nsecs; + + starttime = os::javaTimeNanos(); + } else { + waitspec.tv_sec = 0; + waitspec.tv_nsec = 0; + } kr = semaphore_timedwait(_semaphore, waitspec); while (kr == KERN_ABORTED) { - // reduce the timeout and try again - int64_t totalwait = millis_to_nanos(millis); - int64_t current = os::javaTimeNanos(); - int64_t passedtime = current - starttime; + if (!is_trywait) { + // reduce the timeout and try again + int64_t totalwait = millis_to_nanos(millis); + int64_t current = os::javaTimeNanos(); + int64_t passedtime = current - starttime; - if (passedtime >= totalwait) { - waitspec.tv_sec = 0; - waitspec.tv_nsec = 0; - } else { - int64_t waittime = totalwait - (current - starttime); - waitspec.tv_sec = waittime / NANOSECS_PER_SEC; - waitspec.tv_nsec = waittime % NANOSECS_PER_SEC; + if (passedtime >= totalwait) { + waitspec.tv_sec = 0; + waitspec.tv_nsec = 0; + } else { + int64_t waittime = totalwait - (current - starttime); + waitspec.tv_sec = waittime / NANOSECS_PER_SEC; + waitspec.tv_nsec = waittime % NANOSECS_PER_SEC; + } } kr = semaphore_timedwait(_semaphore, waitspec); From 58d2c1d47db8a7defe2c3319cfab943296cf34f1 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 4 Mar 2026 07:17:26 +0000 Subject: [PATCH 024/655] 8371155: Type annotations on local variables are classified after the local var initializer has been type checked Reviewed-by: vromero --- .../sun/tools/javac/code/TypeAnnotations.java | 94 +++++--- .../com/sun/tools/javac/comp/Attr.java | 5 +- .../TypeAnnotationsOnVariables.java | 211 ++++++++++++++++++ 3 files changed, 283 insertions(+), 27 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 86319f20c73..8eba79c7480 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -50,6 +50,7 @@ import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Type.ModuleType; +import com.sun.tools.javac.code.Type.UnionClassType; import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.AttrContext; @@ -61,6 +62,7 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotatedType; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCCatch; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; @@ -70,6 +72,7 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCTry; import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCTypeIntersection; import com.sun.tools.javac.tree.JCTree.JCTypeParameter; @@ -111,6 +114,7 @@ public class TypeAnnotations { final Symtab syms; final Annotate annotate; final Attr attr; + final Types types; @SuppressWarnings("this-escape") protected TypeAnnotations(Context context) { @@ -120,6 +124,7 @@ public class TypeAnnotations { syms = Symtab.instance(context); annotate = Annotate.instance(context); attr = Attr.instance(context); + types = Types.instance(context); } /** @@ -132,7 +137,24 @@ public class TypeAnnotations { annotate.afterTypes(() -> { JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); try { - new TypeAnnotationPositions(true).scan(tree); + new TypeAnnotationPositions(null, true).scan(tree); + } finally { + log.useSource(oldSource); + } + }); + } + + public void organizeTypeAnnotationsSignaturesForLocalVarType(final Env env, final JCVariableDecl tree) { + annotate.afterTypes(() -> { + JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); + try { + TypeAnnotationPositions pos = new TypeAnnotationPositions(env.tree, true); + if (env.tree instanceof JCLambda) { + pos.push(env.tree); + } else { + pos.push(env.enclMethod); + } + pos.scan(tree); } finally { log.useSource(oldSource); } @@ -155,7 +177,7 @@ public class TypeAnnotations { * top-level blocks, and method bodies, and should be called from Attr. */ public void organizeTypeAnnotationsBodies(JCClassDecl tree) { - new TypeAnnotationPositions(false).scan(tree); + new TypeAnnotationPositions(null, false).scan(tree); } public enum AnnotationType { DECLARATION, TYPE, NONE, BOTH } @@ -265,9 +287,11 @@ public class TypeAnnotations { private class TypeAnnotationPositions extends TreeScanner { + private final JCTree contextTree; private final boolean sigOnly; - TypeAnnotationPositions(boolean sigOnly) { + TypeAnnotationPositions(JCTree contextTree, boolean sigOnly) { + this.contextTree = contextTree; this.sigOnly = sigOnly; } @@ -455,14 +479,15 @@ public class TypeAnnotations { return type.annotatedType(onlyTypeAnnotations); } else if (type.getKind() == TypeKind.UNION) { // There is a TypeKind, but no TypeTag. + UnionClassType ut = (UnionClassType) type; JCTypeUnion tutree = (JCTypeUnion)typetree; JCExpression fst = tutree.alternatives.get(0); Type res = typeWithAnnotations(fst, fst.type, annotations, onlyTypeAnnotations, pos); fst.type = res; - // TODO: do we want to set res as first element in uct.alternatives? - // UnionClassType uct = (com.sun.tools.javac.code.Type.UnionClassType)type; - // Return the un-annotated union-type. - return type; + ListBuffer alternatives = new ListBuffer<>(); + alternatives.add(res); + alternatives.addAll(ut.alternatives_field.tail); + return new UnionClassType((ClassType) ut.getLub(), alternatives.toList()); } else { Type enclTy = type; Element enclEl = type.asElement(); @@ -1237,7 +1262,17 @@ public class TypeAnnotations { } else if (tree.sym == null) { Assert.error("Visiting tree node before memberEnter"); } else if (tree.sym.getKind() == ElementKind.PARAMETER) { - // Parameters are handled in visitMethodDef or visitLambda. + if (sigOnly) { + if (contextTree instanceof JCCatch c && c.param == tree) { + //exception "parameter": + final TypeAnnotationPosition pos = + TypeAnnotationPosition.exceptionParameter(currentLambda, + tree.pos); + separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + } else { + // (real) parameters are handled in visitMethodDef or visitLambda. + } + } } else if (tree.sym.getKind() == ElementKind.FIELD) { if (sigOnly) { TypeAnnotationPosition pos = @@ -1245,27 +1280,36 @@ public class TypeAnnotations { separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); } } else if (tree.sym.getKind() == ElementKind.LOCAL_VARIABLE) { - final TypeAnnotationPosition pos = - TypeAnnotationPosition.localVariable(currentLambda, - tree.pos); - if (!tree.declaredUsingVar()) { - separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + if (sigOnly && !tree.declaredUsingVar()) { + if (contextTree instanceof JCTry t && t.resources.contains(tree)) { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.resourceVariable(currentLambda, + tree.pos); + separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + } else { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.localVariable(currentLambda, + tree.pos); + if (!tree.declaredUsingVar()) { + separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + } + } } } else if (tree.sym.getKind() == ElementKind.BINDING_VARIABLE) { - final TypeAnnotationPosition pos = - TypeAnnotationPosition.localVariable(currentLambda, - tree.pos); - separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + if (sigOnly) { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.localVariable(currentLambda, + tree.pos); + separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + } } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { - final TypeAnnotationPosition pos = - TypeAnnotationPosition.exceptionParameter(currentLambda, - tree.pos); - separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + if (sigOnly) { + Assert.error("Should not get variable kind: " + tree.sym.getKind()); + } } else if (tree.sym.getKind() == ElementKind.RESOURCE_VARIABLE) { - final TypeAnnotationPosition pos = - TypeAnnotationPosition.resourceVariable(currentLambda, - tree.pos); - separateAnnotationsKinds(tree, tree.vartype, tree.sym.type, tree.sym, pos); + if (sigOnly) { + Assert.error("Should not get variable kind: " + tree.sym.getKind()); + } } else if (tree.sym.getKind() == ElementKind.ENUM_CONSTANT) { // No type annotations can occur here. } else { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 83b684e1225..444530c7266 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1281,6 +1281,7 @@ public class Attr extends JCTree.Visitor { try { annotate.blockAnnotations(); memberEnter.memberEnter(tree, env); + typeAnnotations.organizeTypeAnnotationsSignaturesForLocalVarType(env, tree); } finally { annotate.unblockAnnotations(); } @@ -4226,7 +4227,6 @@ public class Attr extends JCTree.Visitor { } else { type = resultInfo.pt; } - tree.type = tree.var.type = type; BindingSymbol v = new BindingSymbol(tree.var.mods.flags | tree.var.declKind.additionalSymbolFlags, tree.var.name, type, env.info.scope.owner); v.pos = tree.pos; @@ -4244,7 +4244,8 @@ public class Attr extends JCTree.Visitor { annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v); } annotate.flush(); - result = tree.type; + typeAnnotations.organizeTypeAnnotationsSignaturesForLocalVarType(env, tree.var); + result = tree.type = tree.var.type = v.type; if (v.isUnnamedVariable()) { matchBindings = MatchBindingsComputer.EMPTY; } else { diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java new file mode 100644 index 00000000000..2e68e18f8f7 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8371155 + * @summary Verify type annotations on local-like variables are propagated to + * their types at an appropriate time. + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run main TypeAnnotationsOnVariables + */ + +import com.sun.source.tree.LambdaExpressionTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.UnionType; +import toolbox.JavacTask; +import toolbox.ToolBox; + +public class TypeAnnotationsOnVariables { + + public static void main(String... args) throws Exception { + new TypeAnnotationsOnVariables().run(); + } + + ToolBox tb = new ToolBox(); + + void run() throws Exception { + typeAnnotationInConstantExpressionFieldInit(Paths.get(".")); + } + + void typeAnnotationInConstantExpressionFieldInit(Path base) throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + import java.util.function.Supplier; + + class Test { + @Target(ElementType.TYPE_USE) + @interface TypeAnno { } + + @TypeAnno Supplier r_f_i = () -> "r_f_i"; + static @TypeAnno Supplier r_f_s = () -> "r_f_s"; + + { + @TypeAnno Supplier r_init_i = () -> "r_init_i"; + } + + static { + @TypeAnno Supplier r_init_s = () -> "r_init_s"; + } + + void m() { + @TypeAnno Supplier r_m_i = () -> "r_m_i"; + } + + static void g() { + @TypeAnno Supplier r_g_s = () -> "r_g_s"; + } + + void h() { + t_cr(() -> "t_cr"); + } + + void i() { + t_no_cr((@TypeAnno Supplier)() -> "t_no_cr"); + } + + void j() { + t_no_cr((java.io.Serializable & @TypeAnno Supplier)() -> "t_no_cr"); + } + + void k() throws Throwable { + try (@TypeAnno AutoCloseable ac = () -> {}) {} + } + + void l() { + try { + } catch (@TypeAnno Exception e1) {} + } + + void n() { + try { + } catch (@TypeAnno final Exception e2) {} + } + + void o() { + try { + } catch (@TypeAnno IllegalStateException | @TypeAnno NullPointerException | IllegalArgumentException e3) {} + } + + void t_cr(@TypeAnno Supplier r_p) { } + void t_no_cr(@TypeAnno Supplier r_p) { } + } + """); + Files.createDirectories(classes); + List actual = new ArrayList<>(); + new JavacTask(tb) + .options("-d", classes.toString()) + .files(tb.findJavaFiles(src)) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitVariable(VariableTree node, Void p) { + actual.add(node.getName() + ": " + typeToString(trees.getTypeMirror(getCurrentPath()))); + return super.visitVariable(node, p); + } + @Override + public Void visitLambdaExpression(LambdaExpressionTree node, Void p) { + actual.add(treeToString(node)+ ": " + typeToString(trees.getTypeMirror(getCurrentPath()))); + return super.visitLambdaExpression(node, p); + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run() + .writeAll(); + + List expected = List.of( + "r_f_i: java.util.function.@Test.TypeAnno Supplier", + "()->\"r_f_i\": java.util.function.@Test.TypeAnno Supplier", + "r_f_s: java.util.function.@Test.TypeAnno Supplier", + "()->\"r_f_s\": java.util.function.@Test.TypeAnno Supplier", + "r_init_i: java.util.function.@Test.TypeAnno Supplier", + "()->\"r_init_i\": java.util.function.@Test.TypeAnno Supplier", + "r_init_s: java.util.function.@Test.TypeAnno Supplier", + "()->\"r_init_s\": java.util.function.@Test.TypeAnno Supplier", + "r_m_i: java.util.function.@Test.TypeAnno Supplier", + "()->\"r_m_i\": java.util.function.@Test.TypeAnno Supplier", + "r_g_s: java.util.function.@Test.TypeAnno Supplier", + "()->\"r_g_s\": java.util.function.@Test.TypeAnno Supplier", + "()->\"t_cr\": java.util.function.@Test.TypeAnno Supplier", + "()->\"t_no_cr\": java.util.function.@Test.TypeAnno Supplier", + "()->\"t_no_cr\": java.lang.Object&java.io.Serializable&java.util.function.@Test.TypeAnno Supplier", + "ac: java.lang.@Test.TypeAnno AutoCloseable", + "()->{ }: java.lang.@Test.TypeAnno AutoCloseable", + "e1: java.lang.@Test.TypeAnno Exception", + "e2: java.lang.@Test.TypeAnno Exception", + "e3: java.lang.@Test.TypeAnno IllegalStateException | java.lang.@Test.TypeAnno NullPointerException | java.lang.IllegalArgumentException", + "r_p: java.util.function.@Test.TypeAnno Supplier", + "r_p: java.util.function.@Test.TypeAnno Supplier" + ); + + actual.forEach(System.out::println); + if (!expected.equals(actual)) { + throw new AssertionError("Expected: " + expected + ", but got: " + actual); + } + } + + static String typeToString(TypeMirror type) { + if (type != null && type.getKind() == TypeKind.UNION) { + return ((UnionType) type).getAlternatives().stream().map(t -> typeToString(t)).collect(Collectors.joining(" | ")); + } else { + return String.valueOf(type); + } + } + + static String treeToString(Tree tree) { + if (tree.toString().contains("\n")) { + System.err.println("!!!"); + } + return String.valueOf(tree).replaceAll("\\R", " "); + } +} From f7918df73318892cf2330812669f9c263f513127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Wed, 4 Mar 2026 07:40:44 +0000 Subject: [PATCH 025/655] 8378779: NBody demo test times out with C1 stress testing Reviewed-by: epeter, dfenacci --- .../jtreg/compiler/gallery/TestParticleLife.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java b/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java index e0fb6164acf..bb1eea927c7 100644 --- a/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java +++ b/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java @@ -91,7 +91,7 @@ public class TestParticleLife { ParticleLife.State state = new ParticleLife.State(); @Test - @Warmup(100) + @Warmup(75) @IR(counts = {IRNode.REPLICATE_F, "> 0", IRNode.LOAD_VECTOR_F, "> 0", IRNode.SUB_VF, "> 0", @@ -109,7 +109,7 @@ public class TestParticleLife { } @Test - @Warmup(10) + @Warmup(2) @IR(counts = {IRNode.REPLICATE_F, "= 0", IRNode.LOAD_VECTOR_F, "= 0", IRNode.REPLICATE_I, "= 0", @@ -138,7 +138,7 @@ public class TestParticleLife { } @Test - @Warmup(10) + @Warmup(2) @IR(counts = {IRNode.REPLICATE_F, "> 0", IRNode.LOAD_VECTOR_F, "> 0", IRNode.REPLICATE_I, "> 0", @@ -164,7 +164,7 @@ public class TestParticleLife { } @Test - @Warmup(10) + @Warmup(2) @IR(counts = {IRNode.REPLICATE_F, "> 0", IRNode.LOAD_VECTOR_F, "> 0", IRNode.REPLICATE_I, "= 0", // No gather operation @@ -191,7 +191,7 @@ public class TestParticleLife { @Test - @Warmup(10) + @Warmup(2) @IR(counts = {IRNode.REPLICATE_F, "> 0", IRNode.LOAD_VECTOR_F, "> 0", IRNode.REPLICATE_I, "> 0", From 5ab9ddf5e2fa31caa0f62736aff96dd8c12e0177 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 4 Mar 2026 09:32:05 +0000 Subject: [PATCH 026/655] 8378138: G1: Assertion failure from G1CollectedHeap::block_start processing during error reporting Co-authored-by: Yasumasa Suenaga Reviewed-by: ysuenaga, iwalulya --- src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index 4f242b7a537..f92e37fee3c 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -42,6 +42,11 @@ #include "utilities/globalDefinitions.hpp" inline HeapWord* G1HeapRegion::block_start(const void* addr) const { + if (is_young()) { + // We are here because of BlockLocationPrinter. + // Can be invoked in any context, so this region might not be parsable. + return nullptr; + } return block_start(addr, parsable_bottom_acquire()); } @@ -64,6 +69,7 @@ inline HeapWord* G1HeapRegion::advance_to_block_containing_addr(const void* addr inline HeapWord* G1HeapRegion::block_start(const void* addr, HeapWord* const pb) const { assert(addr >= bottom() && addr < top(), "invalid address"); + assert(!is_young(), "Only non-young regions have BOT"); HeapWord* first_block = _bot->block_start_reaching_into_card(addr); return advance_to_block_containing_addr(addr, pb, first_block); } From f26b379b97301aca49dda9cb5dfe9a5472af7140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Wed, 4 Mar 2026 09:49:24 +0000 Subject: [PATCH 027/655] 8378927: H3MultipleConnectionsToSameHost.java#with-continuations intermittent fails Reviewed-by: syan, dfuchs --- .../http3/H3MultipleConnectionsToSameHost.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java index 67ac821b6f7..f9ba35359bc 100644 --- a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java +++ b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java @@ -30,6 +30,9 @@ * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=360 -XX:+CrashOnOutOfMemoryError + * -Djdk.httpclient.quic.idleTimeout=100000 + * -Djdk.httpclient.keepalive.timeout.h3=100000 + * -Djdk.test.server.quic.idleTimeout=100000 * -Djdk.httpclient.quic.minPtoBackoffTime=60 * -Djdk.httpclient.quic.maxPtoBackoffTime=90 * -Djdk.httpclient.quic.maxPtoBackoff=10 @@ -53,6 +56,9 @@ * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=360 -XX:+CrashOnOutOfMemoryError + * -Djdk.httpclient.quic.idleTimeout=100000 + * -Djdk.httpclient.keepalive.timeout.h3=100000 + * -Djdk.test.server.quic.idleTimeout=100000 * -Djdk.httpclient.quic.minPtoBackoffTime=45 * -Djdk.httpclient.quic.maxPtoBackoffTime=60 * -Djdk.httpclient.quic.maxPtoBackoff=9 @@ -76,9 +82,9 @@ * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=360 -XX:+CrashOnOutOfMemoryError - * -Djdk.httpclient.quic.idleTimeout=120 - * -Djdk.httpclient.keepalive.timeout.h3=120 - * -Djdk.test.server.quic.idleTimeout=90 + * -Djdk.httpclient.quic.idleTimeout=100000 + * -Djdk.httpclient.keepalive.timeout.h3=100000 + * -Djdk.test.server.quic.idleTimeout=100000 * -Djdk.httpclient.quic.minPtoBackoffTime=60 * -Djdk.httpclient.quic.maxPtoBackoffTime=120 * -Djdk.httpclient.quic.maxPtoBackoff=9 @@ -101,9 +107,9 @@ * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=360 -XX:+CrashOnOutOfMemoryError - * -Djdk.httpclient.quic.idleTimeout=120 - * -Djdk.httpclient.keepalive.timeout.h3=120 - * -Djdk.test.server.quic.idleTimeout=90 + * -Djdk.httpclient.quic.idleTimeout=100000 + * -Djdk.httpclient.keepalive.timeout.h3=100000 + * -Djdk.test.server.quic.idleTimeout=100000 * -Djdk.httpclient.quic.minPtoBackoffTime=60 * -Djdk.httpclient.quic.maxPtoBackoffTime=120 * -Djdk.httpclient.quic.maxPtoBackoff=9 From d78a13a7cce07b28668ed88f209f94693f0e607f Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 4 Mar 2026 10:39:42 +0000 Subject: [PATCH 028/655] 8366138: Parse::jump_switch_ranges() could cause stack overflow when compiling huge switch statement Reviewed-by: rasbold, dfenacci, mchevalier --- src/hotspot/share/opto/parse2.cpp | 53 +++++++--- .../compiler/c2/TestSwitchStackOverflow.java | 99 +++++++++++++++++++ 2 files changed, 136 insertions(+), 16 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestSwitchStackOverflow.java diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index eac2b3e863a..7f41870ccea 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -966,12 +966,28 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, _max_switch_depth = 0; _est_switch_depth = log2i_graceful((hi - lo + 1) - 1) + 1; } + SwitchRange* orig_lo = lo; + SwitchRange* orig_hi = hi; #endif - assert(lo <= hi, "must be a non-empty set of ranges"); - if (lo == hi) { - jump_if_always_fork(lo->dest(), trim_ranges && lo->cnt() == 0); - } else { + // The lower-range processing is done iteratively to avoid O(N) stack depth + // when the profiling-based pivot repeatedly selects mid==lo (JDK-8366138). + // The upper-range processing remains recursive but is only reached for + // balanced splits, bounding its depth to O(log N). + // Termination: every iteration either exits or strictly decreases hi-lo: + // lo == mid && mid < hi, increments lo + // lo < mid <= hi, sets hi = mid - 1. + for (int depth = switch_depth;; depth++) { +#ifndef PRODUCT + _max_switch_depth = MAX2(depth, _max_switch_depth); +#endif + + assert(lo <= hi, "must be a non-empty set of ranges"); + if (lo == hi) { + jump_if_always_fork(lo->dest(), trim_ranges && lo->cnt() == 0); + break; + } + assert(lo->hi() == (lo+1)->lo()-1, "contiguous ranges"); assert(hi->lo() == (hi-1)->hi()+1, "contiguous ranges"); @@ -981,7 +997,12 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, float total_cnt = sum_of_cnts(lo, hi); int nr = hi - lo + 1; - if (UseSwitchProfiling) { + // With total_cnt==0 the profiling pivot degenerates to mid==lo + // (0 >= 0/2), producing a linear chain of If nodes instead of a + // balanced tree. A balanced tree is strictly better here: all paths + // are cold, so a balanced split gives fewer comparisons at runtime + // and avoids pathological memory usage in the optimizer. + if (UseSwitchProfiling && total_cnt > 0) { // Don't keep the binary search tree balanced: pick up mid point // that split frequencies in half. float cnt = 0; @@ -1002,7 +1023,7 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, assert(nr != 2 || mid == hi, "should pick higher of 2"); assert(nr != 3 || mid == hi-1, "should pick middle of 3"); } - + assert(mid != nullptr, "mid must be set"); Node *test_val = _gvn.intcon(mid == lo ? mid->hi() : mid->lo()); @@ -1025,7 +1046,7 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, Node *iffalse = _gvn.transform( new IfFalseNode(iff_lt) ); { PreserveJVMState pjvms(this); set_control(iffalse); - jump_switch_ranges(key_val, mid+1, hi, switch_depth+1); + jump_switch_ranges(key_val, mid+1, hi, depth+1); } set_control(iftrue); } @@ -1043,21 +1064,22 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, Node *iffalse = _gvn.transform( new IfFalseNode(iff_ge) ); { PreserveJVMState pjvms(this); set_control(iftrue); - jump_switch_ranges(key_val, mid == lo ? mid+1 : mid, hi, switch_depth+1); + jump_switch_ranges(key_val, mid == lo ? mid+1 : mid, hi, depth+1); } set_control(iffalse); } } - // in any case, process the lower range + // Process the lower range: iterate instead of recursing. if (mid == lo) { if (mid->is_singleton()) { - jump_switch_ranges(key_val, lo+1, hi, switch_depth+1); + lo++; } else { jump_if_always_fork(lo->dest(), trim_ranges && lo->cnt() == 0); + break; } } else { - jump_switch_ranges(key_val, lo, mid-1, switch_depth+1); + hi = mid - 1; } } @@ -1072,23 +1094,22 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, } #ifndef PRODUCT - _max_switch_depth = MAX2(switch_depth, _max_switch_depth); if (TraceOptoParse && Verbose && WizardMode && switch_depth == 0) { SwitchRange* r; int nsing = 0; - for( r = lo; r <= hi; r++ ) { + for (r = orig_lo; r <= orig_hi; r++) { if( r->is_singleton() ) nsing++; } tty->print(">>> "); _method->print_short_name(); tty->print_cr(" switch decision tree"); tty->print_cr(" %d ranges (%d singletons), max_depth=%d, est_depth=%d", - (int) (hi-lo+1), nsing, _max_switch_depth, _est_switch_depth); + (int) (orig_hi-orig_lo+1), nsing, _max_switch_depth, _est_switch_depth); if (_max_switch_depth > _est_switch_depth) { tty->print_cr("******** BAD SWITCH DEPTH ********"); } tty->print(" "); - for( r = lo; r <= hi; r++ ) { + for (r = orig_lo; r <= orig_hi; r++) { r->print(); } tty->cr(); diff --git a/test/hotspot/jtreg/compiler/c2/TestSwitchStackOverflow.java b/test/hotspot/jtreg/compiler/c2/TestSwitchStackOverflow.java new file mode 100644 index 00000000000..adbfa537aed --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestSwitchStackOverflow.java @@ -0,0 +1,99 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8366138 + * @summary C2: jump_switch_ranges could cause stack overflow when compiling + * huge switch statement with zero-count profiling data. + * @library /test/lib / + * @run main/othervm ${test.main.class} + * @run main/othervm -Xbatch -XX:CompileOnly=Test::test -XX:-DontCompileHugeMethods -XX:CompilerThreadStackSize=512 ${test.main.class} + * @run main/othervm -Xbatch -XX:CompileOnly=Test::test -XX:+DontCompileHugeMethods -XX:CompilerThreadStackSize=512 ${test.main.class} + */ + +package compiler.c2; + +import java.util.stream.Stream; + +import compiler.lib.compile_framework.CompileFramework; +import compiler.lib.template_framework.Template; +import static compiler.lib.template_framework.Template.scope; + +public class TestSwitchStackOverflow { + // Template method exceeds HugeMethodLimit, hence -XX:-DontCompileHugeMethods. + // 5000 cases + CompilerThreadStackSize=512 reliably overflows without the fix. + static final int NUM_CASES = 5000; + + // Generate a class with a large tableswitch method and a main that + // triggers recompilation with zero-count profiling data: + // Phase 1: warm up with default-only path -> C2 compiles + // Phase 2: hit a case -> triggers unstable_if deopt + // Phase 3: recompile with all counts zero (except the default case) + static String generate() { + var caseTemplate = Template.make("i", (Integer i) -> scope( + """ + case #i: + return #i; + """ + )); + var test = Template.make(() -> scope( + """ + public class Test { + static int test(int x) { + switch (x) { + """, + Stream.iterate(0, i -> i + 1) + .limit(NUM_CASES) + .map(i -> caseTemplate.asToken(i)) + .toList(), + """ + default: return -1; + } + } + + public static void main(String[] args) { + for (int i = 0; i < 10_000; i++) { + test(-1); + } + test(42); + for (int i = 0; i < 10_000; i++) { + test(-1); + } + System.out.println("Done"); + } + } + """ + )); + + return test.render(); + } + + public static void main(String[] args) { + CompileFramework comp = new CompileFramework(); + comp.addJavaSourceCode("Test", generate()); + comp.compile(); + comp.invoke("Test", "main", new Object[] { new String[0] }); + } +} From 329e14b0744912293faa7769b22fa348cb1d10aa Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 4 Mar 2026 10:56:49 +0000 Subject: [PATCH 029/655] 8375688: C2: Missed Ideal optimization opportunity with VectorMaskToLong and -XX:+StressIncrementalInlining Reviewed-by: qamai, dfenacci --- src/hotspot/share/opto/phaseX.cpp | 10 + .../vectorapi/TestVectorMaskToLongStress.java | 180 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorMaskToLongStress.java diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 3cbbc114778..bc0bed31370 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -2725,6 +2725,16 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ worklist.push(cmp); } } + // VectorMaskToLongNode::Ideal_MaskAll looks through VectorStoreMask + // to fold constant masks. + if (use_op == Op_VectorStoreMask) { + for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { + Node* u = use->fast_out(i2); + if (u->Opcode() == Op_VectorMaskToLong) { + worklist.push(u); + } + } + } // From CastX2PNode::Ideal // CastX2P(AddX(x, y)) diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorMaskToLongStress.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorMaskToLongStress.java new file mode 100644 index 00000000000..f9807754539 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorMaskToLongStress.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8375688 + * @key randomness + * @library /test/lib / + * @summary VectorMaskToLong constant folding through VectorStoreMask must work under StressIncrementalInlining + * @modules jdk.incubator.vector + * + * @run driver ${test.main.class} + */ + +package compiler.vectorapi; + +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/** + * Tests that VectorMaskToLongNode::Ideal_MaskAll folds constant masks even + * when StressIncrementalInlining randomizes the IGVN worklist order. + * + * Each test method does {@code VectorMask.fromLong(SPECIES, constant).toLong()} + * and asserts that VectorMaskToLong is folded away entirely (count = 0). + * + * Ideal_MaskAll looks through VectorStoreMask to inspect its input. Without the worklist + * propagation fix in PhaseIterGVN::add_users_of_use_to_worklist (JDK-8375688), VectorMaskToLong + * is not re-visited after VectorStoreMask's input becomes a recognized constant, + * leaving the fold opportunity missed. + * + * IR rules cover three hardware paths: + * - AVX-512/SVE/RVV: masks fold through MaskAll (correctness check only, VectorStoreMask + * is not involved on these platforms) + * - AVX2 without AVX-512: masks go through VectorStoreMask, directly exercising the worklist fix + * - ASIMD without SVE: same VectorStoreMask path, on AArch64 + * + * {@code @Check} methods verify correctness on all platforms, including those where no IR rule applies. + * Float/Double species are excluded because VectorMaskToLong fails to fold their masks + * due to an intervening VectorMaskCast (JDK-8377588). + */ +public class TestVectorMaskToLongStress { + static final VectorSpecies B_SPECIES = ByteVector.SPECIES_MAX; + static final VectorSpecies S_SPECIES = ShortVector.SPECIES_MAX; + static final VectorSpecies I_SPECIES = IntVector.SPECIES_MAX; + static final VectorSpecies L_SPECIES = LongVector.SPECIES_MAX; + + // --- All-ones mask: fromLong(-1).toLong() should fold to a constant --- + + @Test + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureOr = { "avx512", "true", "sve", "true", "rvv", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + public static long testAllOnesByte() { + return VectorMask.fromLong(B_SPECIES, -1L).toLong(); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureOr = { "avx512", "true", "sve", "true", "rvv", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + public static long testAllOnesShort() { + return VectorMask.fromLong(S_SPECIES, -1L).toLong(); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureOr = { "avx512", "true", "sve", "true", "rvv", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + public static long testAllOnesInt() { + return VectorMask.fromLong(I_SPECIES, -1L).toLong(); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureOr = { "avx512", "true", "sve", "true", "rvv", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + public static long testAllOnesLong() { + return VectorMask.fromLong(L_SPECIES, -1L).toLong(); + } + + // --- All-zeros mask: fromLong(0).toLong() should fold to a constant --- + + @Test + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureOr = { "avx512", "true", "sve", "true", "rvv", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + public static long testAllZerosByte() { + return VectorMask.fromLong(B_SPECIES, 0L).toLong(); + } + + @Test + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureOr = { "avx512", "true", "sve", "true", "rvv", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 0" }, + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + public static long testAllZerosInt() { + return VectorMask.fromLong(I_SPECIES, 0L).toLong(); + } + + // --- Verification --- + + @Check(test = "testAllOnesByte") + public static void checkAllOnesByte(long result) { + Asserts.assertEquals(-1L >>> (64 - B_SPECIES.length()), result); + } + + @Check(test = "testAllOnesShort") + public static void checkAllOnesShort(long result) { + Asserts.assertEquals(-1L >>> (64 - S_SPECIES.length()), result); + } + + @Check(test = "testAllOnesInt") + public static void checkAllOnesInt(long result) { + Asserts.assertEquals(-1L >>> (64 - I_SPECIES.length()), result); + } + + @Check(test = "testAllOnesLong") + public static void checkAllOnesLong(long result) { + Asserts.assertEquals(-1L >>> (64 - L_SPECIES.length()), result); + } + + @Check(test = "testAllZerosByte") + public static void checkAllZerosByte(long result) { + Asserts.assertEquals(0L, result); + } + + @Check(test = "testAllZerosInt") + public static void checkAllZerosInt(long result) { + Asserts.assertEquals(0L, result); + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.addFlags("--add-modules=jdk.incubator.vector", + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+StressIncrementalInlining", + "-XX:CompileCommand=compileonly,compiler.vectorapi.TestVectorMaskToLongStress::*", + "-XX:VerifyIterativeGVN=1110") + .start(); + } +} From a3b468cec3997c62a2f55302b0338aa0a2bb3055 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 4 Mar 2026 11:12:40 +0000 Subject: [PATCH 030/655] 8379119: G1: Move NoteStartOfMarkHRClosure out of global namespace Reviewed-by: aboldtch, ayang --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 54 +++++++++----------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index ec5649f4fe2..074231a02d4 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -898,9 +898,26 @@ public: }; class G1PreConcurrentStartTask::NoteStartOfMarkTask : public G1AbstractSubTask { + + class NoteStartOfMarkHRClosure : public G1HeapRegionClosure { + G1ConcurrentMark* _cm; + + public: + NoteStartOfMarkHRClosure() : G1HeapRegionClosure(), _cm(G1CollectedHeap::heap()->concurrent_mark()) { } + + bool do_heap_region(G1HeapRegion* r) override { + if (r->is_old_or_humongous() && !r->is_collection_set_candidate() && !r->in_collection_set()) { + _cm->update_top_at_mark_start(r); + } else { + _cm->reset_top_at_mark_start(r); + } + return false; + } + } _region_cl; + G1HeapRegionClaimer _claimer; public: - NoteStartOfMarkTask() : G1AbstractSubTask(G1GCPhaseTimes::NoteStartOfMark), _claimer(0) { } + NoteStartOfMarkTask() : G1AbstractSubTask(G1GCPhaseTimes::NoteStartOfMark), _region_cl(), _claimer(0) { } double worker_cost() const override { // The work done per region is very small, therefore we choose this magic number to cap the number @@ -909,8 +926,13 @@ public: return _claimer.n_regions() / regions_per_thread; } - void set_max_workers(uint max_workers) override; - void do_work(uint worker_id) override; + void set_max_workers(uint max_workers) override { + _claimer.set_n_workers(max_workers); + } + + void do_work(uint worker_id) override { + G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&_region_cl, &_claimer, worker_id); + } }; void G1PreConcurrentStartTask::ResetMarkingStateTask::do_work(uint worker_id) { @@ -918,31 +940,6 @@ void G1PreConcurrentStartTask::ResetMarkingStateTask::do_work(uint worker_id) { _cm->reset(); } -class NoteStartOfMarkHRClosure : public G1HeapRegionClosure { - G1ConcurrentMark* _cm; - -public: - NoteStartOfMarkHRClosure() : G1HeapRegionClosure(), _cm(G1CollectedHeap::heap()->concurrent_mark()) { } - - bool do_heap_region(G1HeapRegion* r) override { - if (r->is_old_or_humongous() && !r->is_collection_set_candidate() && !r->in_collection_set()) { - _cm->update_top_at_mark_start(r); - } else { - _cm->reset_top_at_mark_start(r); - } - return false; - } -}; - -void G1PreConcurrentStartTask::NoteStartOfMarkTask::do_work(uint worker_id) { - NoteStartOfMarkHRClosure start_cl; - G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&start_cl, &_claimer, worker_id); -} - -void G1PreConcurrentStartTask::NoteStartOfMarkTask::set_max_workers(uint max_workers) { - _claimer.set_n_workers(max_workers); -} - G1PreConcurrentStartTask::G1PreConcurrentStartTask(GCCause::Cause cause, G1ConcurrentMark* cm) : G1BatchedTask("Pre Concurrent Start", G1CollectedHeap::heap()->phase_times()) { add_serial_task(new ResetMarkingStateTask(cm)); @@ -962,7 +959,6 @@ void G1ConcurrentMark::pre_concurrent_start(GCCause::Cause cause) { _gc_tracer_cm->set_gc_cause(cause); } - void G1ConcurrentMark::post_concurrent_mark_start() { // Start Concurrent Marking weak-reference discovery. ReferenceProcessor* rp = _g1h->ref_processor_cm(); From ff8b0ac048f6a6f75d1ad738d3354890d76d8128 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Wed, 4 Mar 2026 11:45:09 +0000 Subject: [PATCH 031/655] 8214934: Wrong type annotation offset on casts on expressions Reviewed-by: jlahoda --- .../com/sun/tools/javac/comp/TransTypes.java | 24 ++- .../IncorrectCastOffsetTest.java | 175 ++++++++++++++++++ 2 files changed, 194 insertions(+), 5 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index 862c02ea5f0..1229939c0bf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -29,7 +29,6 @@ package com.sun.tools.javac.comp; import com.sun.source.tree.MemberReferenceTree.ReferenceMode; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Attribute.TypeCompound; -import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.TypeVar; import com.sun.tools.javac.jvm.Target; @@ -49,8 +48,6 @@ import static com.sun.tools.javac.code.TypeTag.VOID; import static com.sun.tools.javac.comp.CompileStates.CompileState; import com.sun.tools.javac.tree.JCTree.JCBreak; -import javax.lang.model.type.TypeKind; - /** This pass translates Generic Java to conventional Java. * *

This is NOT part of any supported API. @@ -109,7 +106,9 @@ public class TransTypes extends TreeTranslator { if (!types.isSameType(tree.type, target)) { if (!resolve.isAccessible(env, target.tsym)) resolve.logAccessErrorInternal(env, tree, target); - tree = make.TypeCast(make.Type(target), tree).setType(target); + tree = explicitCastTP != null && types.isSameType(target, explicitCastTP) ? + tree : + make.TypeCast(make.Type(target), tree).setType(target); } make.pos = oldpos; return tree; @@ -440,16 +439,29 @@ public class TransTypes extends TreeTranslator { /** Visitor argument: proto-type. */ private Type pt; + /** we use this type to indicate that "upstream" there is an explicit cast to this type, + * this way we can avoid generating redundant type casts. Redundant casts are not + * innocuous as they can trump user provided ones and affect the offset + * calculation of type annotations applied to the user provided type cast. + */ + private Type explicitCastTP; /** Visitor method: perform a type translation on tree. */ public T translate(T tree, Type pt) { + return translate(tree, pt, pt == explicitCastTP ? explicitCastTP : null); + } + + public T translate(T tree, Type pt, Type castTP) { Type prevPt = this.pt; + Type prevCastPT = this.explicitCastTP; try { this.pt = pt; + this.explicitCastTP = castTP; return translate(tree); } finally { this.pt = prevPt; + this.explicitCastTP = prevCastPT; } } @@ -1037,7 +1049,9 @@ public class TransTypes extends TreeTranslator { tree.clazz = translate(tree.clazz, null); Type originalTarget = tree.type; tree.type = erasure(tree.type); - JCExpression newExpression = translate(tree.expr, tree.type); + JCExpression newExpression = tree.clazz.hasTag(Tag.ANNOTATED_TYPE) ? + translate(tree.expr, tree.type, tree.type) : + translate(tree.expr, tree.type); if (newExpression != tree.expr) { JCTypeCast typeCast = newExpression.hasTag(Tag.TYPECAST) ? (JCTypeCast) newExpression diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java new file mode 100644 index 00000000000..f679926bcf4 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8214934 + * @summary Wrong type annotation offset on casts on expressions + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap + * @build toolbox.ToolBox toolbox.JavapTask + * @run compile IncorrectCastOffsetTest.java + * @run main IncorrectCastOffsetTest + */ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import java.util.List; + +import toolbox.JavapTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class IncorrectCastOffsetTest { + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + @interface TypeUse {} + + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + @interface TypeUse2 {} + + class AnnotatedCast1 { + private static String checkcast(boolean test, Object obj, Object obj2) { + return (@TypeUse String)(test ? obj : obj2); + } + } + + class AnnotatedCast2 { + private static String checkcast(Object obj) { + return (@TypeUse String)(obj); + } + } + + class AnnotatedCast3 { + private static String checkcast(boolean test, Object obj, Object obj2) { + return (@TypeUse @TypeUse2 String)(test ? obj : obj2); + } + } + + class AnnotatedCast4 { + private static String checkcast(Object obj) { + return (@TypeUse String)(@TypeUse2 CharSequence)(obj); + } + } + + ToolBox tb; + + IncorrectCastOffsetTest() { + tb = new ToolBox(); + } + + public static void main(String args[]) { + IncorrectCastOffsetTest incorrectCastOffsetTest = new IncorrectCastOffsetTest(); + incorrectCastOffsetTest.run(); + } + + void run() { + test("IncorrectCastOffsetTest$AnnotatedCast1.class", + /* + * generated code: + * 0: iload_0 + * 1: ifeq 8 + * 4: aload_1 + * 5: goto 9 + * 8: aload_2 + * 9: checkcast #13 // class java/lang/String + * 12: areturn + */ + List.of( + "RuntimeVisibleTypeAnnotations:", + "0: #35(): CAST, offset=9, type_index=0" + ) + ); + test("IncorrectCastOffsetTest$AnnotatedCast2.class", + /* + * generated code: + * 0: aload_0 + * 1: checkcast #13 // class java/lang/String + * 4: areturn + */ + List.of( + "RuntimeVisibleTypeAnnotations:", + "0: #31(): CAST, offset=1, type_index=0" + ) + ); + test("IncorrectCastOffsetTest$AnnotatedCast3.class", + /* + * generated code: + * 0: iload_0 + * 1: ifeq 8 + * 4: aload_1 + * 5: goto 9 + * 8: aload_2 + * 9: checkcast #13 // class java/lang/String + * 12: areturn + */ + List.of( + "RuntimeVisibleTypeAnnotations:", + "0: #35(): CAST, offset=9, type_index=0", + "IncorrectCastOffsetTest$TypeUse", + "1: #36(): CAST, offset=9, type_index=0", + "IncorrectCastOffsetTest$TypeUse2" + ) + ); + test("IncorrectCastOffsetTest$AnnotatedCast4.class", + /* + * generated code: + * 0: aload_0 + * 1: checkcast #13 // class java/lang/CharSequence + * 4: checkcast #15 // class java/lang/String + * 7: areturn + */ + List.of( + "RuntimeVisibleTypeAnnotations:", + "0: #33(): CAST, offset=4, type_index=0", + "IncorrectCastOffsetTest$TypeUse", + "#34(): CAST, offset=1, type_index=0", + "IncorrectCastOffsetTest$TypeUse2" + ) + ); + } + + void test(String clazz, List expectedOutput) { + Path pathToClass = Paths.get(ToolBox.testClasses, clazz); + String javapOut = new JavapTask(tb) + .options("-v", "-p") + .classes(pathToClass.toString()) + .run() + .getOutput(Task.OutputKind.DIRECT); + + for (String expected : expectedOutput) { + if (!javapOut.contains(expected)) + throw new AssertionError("unexpected output"); + } + } + +} From cb059a6b1b1686b7adcb2e88536060f4f7d47118 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 4 Mar 2026 12:23:31 +0000 Subject: [PATCH 032/655] 8378836: Enable linktime-gc by default on Linux ppc64le Reviewed-by: erikj, jwaters, mdoerr --- make/autoconf/jdk-options.m4 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 87d147d4f07..dafac618c59 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -103,8 +103,12 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS], AC_SUBST(ENABLE_HEADLESS_ONLY) # should we linktime gc unused code sections in the JDK build ? - if test "x$OPENJDK_TARGET_OS" = "xlinux" && test "x$OPENJDK_TARGET_CPU" = xs390x; then - LINKTIME_GC_DEFAULT=true + if test "x$OPENJDK_TARGET_OS" = "xlinux"; then + if test "x$OPENJDK_TARGET_CPU" = "xs390x" || test "x$OPENJDK_TARGET_CPU" = "xppc64le"; then + LINKTIME_GC_DEFAULT=true + else + LINKTIME_GC_DEFAULT=false + fi else LINKTIME_GC_DEFAULT=false fi From d8d543a5dccf126b23d79750c67424e454f97a7f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 4 Mar 2026 13:15:27 +0000 Subject: [PATCH 033/655] 8379121: G1: Remove redundant const_cast in g1BlockOffsetTable Reviewed-by: tschatzl, aboldtch --- src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp | 4 ++-- src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp index fd70796251d..7f0e5e86cd9 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp @@ -73,8 +73,8 @@ void G1BlockOffsetTable::set_offset_array(Atomic* left, Atomic #ifdef ASSERT void G1BlockOffsetTable::check_address(Atomic* addr, const char* msg) const { - Atomic* start_addr = const_cast*>(_offset_base + (uintptr_t(_reserved.start()) >> CardTable::card_shift())); - Atomic* end_addr = const_cast*>(_offset_base + (uintptr_t(_reserved.end()) >> CardTable::card_shift())); + Atomic* start_addr = _offset_base + (uintptr_t(_reserved.start()) >> CardTable::card_shift()); + Atomic* end_addr = _offset_base + (uintptr_t(_reserved.end()) >> CardTable::card_shift()); assert(addr >= start_addr && addr <= end_addr, "%s - offset address: " PTR_FORMAT ", start address: " PTR_FORMAT ", end address: " PTR_FORMAT, msg, (p2i(addr)), (p2i(start_addr)), (p2i(end_addr))); diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp index b707e310781..1236d24bb03 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp @@ -54,7 +54,7 @@ uint8_t G1BlockOffsetTable::offset_array(Atomic* addr) const { inline Atomic* G1BlockOffsetTable::entry_for_addr(const void* const p) const { assert(_reserved.contains(p), "out of bounds access to block offset table"); - Atomic* result = const_cast*>(&_offset_base[uintptr_t(p) >> CardTable::card_shift()]); + Atomic* result = &_offset_base[uintptr_t(p) >> CardTable::card_shift()]; return result; } From 12af936ae47b8c3be9ff639ef550cb63a94f746e Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 4 Mar 2026 13:21:27 +0000 Subject: [PATCH 034/655] 8377986: C2: New method to add specific users to the worklist Reviewed-by: qamai, mchevalier, dfenacci, bmaillard --- src/hotspot/share/opto/phaseX.cpp | 189 +++++++++++------------------- src/hotspot/share/opto/phaseX.hpp | 1 + 2 files changed, 68 insertions(+), 122 deletions(-) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index bc0bed31370..c77316e7d0b 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -360,6 +360,16 @@ NodeHash::~NodeHash() { } #endif +// Add users of 'n' that match 'predicate' to worklist +template +static void add_users_to_worklist_if(Unique_Node_List& worklist, const Node* n, Predicate predicate) { + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* u = n->fast_out(i); + if (predicate(u)) { + worklist.push(u); + } + } +} //============================================================================= //------------------------------PhaseRemoveUseless----------------------------- @@ -2298,12 +2308,7 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { // A Load that directly follows an InitializeNode is // going away. The Stores that follow are candidates // again to be captured by the InitializeNode. - for (DUIterator_Fast jmax, j = in->fast_outs(jmax); j < jmax; j++) { - Node *n = in->fast_out(j); - if (n->is_Store()) { - _worklist.push(n); - } - } + add_users_to_worklist_if(_worklist, in, [](Node* n) { return n->is_Store(); }); } } // if (in != nullptr && in != C->top()) } // for (uint i = 0; i < dead->req(); i++) @@ -2559,41 +2564,29 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ // If changed LShift inputs, check RShift/URShift users for // "(X << C) >> C" sign-ext and "(X << C) >>> C" zero-ext optimizations. if (use_op == Op_LShiftI || use_op == Op_LShiftL) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_RShiftI || u->Opcode() == Op_RShiftL || - u->Opcode() == Op_URShiftI || u->Opcode() == Op_URShiftL) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { + return u->Opcode() == Op_RShiftI || u->Opcode() == Op_RShiftL || + u->Opcode() == Op_URShiftI || u->Opcode() == Op_URShiftL; + }); } // If changed LShift inputs, check And users for shift and mask (And) operation if (use_op == Op_LShiftI || use_op == Op_LShiftL) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_AndI || u->Opcode() == Op_AndL) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { + return u->Opcode() == Op_AndI || u->Opcode() == Op_AndL; + }); } // If changed AddI/SubI inputs, check CmpU for range check optimization. if (use_op == Op_AddI || use_op == Op_SubI) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->is_Cmp() && (u->Opcode() == Op_CmpU)) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { + return u->Opcode() == Op_CmpU; + }); } // If changed AndI/AndL inputs, check RShift/URShift users for "(x & mask) >> shift" optimization opportunity if (use_op == Op_AndI || use_op == Op_AndL) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_RShiftI || u->Opcode() == Op_RShiftL || - u->Opcode() == Op_URShiftI || u->Opcode() == Op_URShiftL) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { + return u->Opcode() == Op_RShiftI || u->Opcode() == Op_RShiftL || + u->Opcode() == Op_URShiftI || u->Opcode() == Op_URShiftL; + }); } // Check for redundant conversion patterns: // ConvD2L->ConvL2D->ConvD2L @@ -2606,35 +2599,22 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ use_op == Op_ConvI2F || use_op == Op_ConvL2F || use_op == Op_ConvF2I) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if ((use_op == Op_ConvL2D && u->Opcode() == Op_ConvD2L) || - (use_op == Op_ConvI2F && u->Opcode() == Op_ConvF2I) || - (use_op == Op_ConvL2F && u->Opcode() == Op_ConvF2L) || - (use_op == Op_ConvF2I && u->Opcode() == Op_ConvI2F)) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [=](Node* u) { + return (use_op == Op_ConvL2D && u->Opcode() == Op_ConvD2L) || + (use_op == Op_ConvI2F && u->Opcode() == Op_ConvF2I) || + (use_op == Op_ConvL2F && u->Opcode() == Op_ConvF2L) || + (use_op == Op_ConvF2I && u->Opcode() == Op_ConvI2F); + }); } // ConvD2F::Ideal matches ConvD2F(SqrtD(ConvF2D(x))) => SqrtF(x). // Notify ConvD2F users of SqrtD when any input of the SqrtD changes. if (use_op == Op_SqrtD) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_ConvD2F) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { return u->Opcode() == Op_ConvD2F; }); } // ConvF2HF::Ideal matches ConvF2HF(binopF(ConvHF2F(...))) => FP16BinOp(...). // Notify ConvF2HF users of float binary ops when any input changes. if (Float16NodeFactory::is_float32_binary_oper(use_op)) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_ConvF2HF) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { return u->Opcode() == Op_ConvF2HF; }); } // If changed AddP inputs: // - check Stores for loop invariant, and @@ -2642,33 +2622,21 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ // address expression flattening. if (use_op == Op_AddP) { bool offset_changed = n == use->in(AddPNode::Offset); - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->is_Mem()) { - worklist.push(u); - } else if (offset_changed && u->is_AddP() && u->in(AddPNode::Offset)->is_Con()) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [=](Node* u) { + return u->is_Mem() || + (offset_changed && u->is_AddP() && u->in(AddPNode::Offset)->is_Con()); + }); } // Check for "abs(0-x)" into "abs(x)" conversion if (use->is_Sub()) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_AbsD || u->Opcode() == Op_AbsF || - u->Opcode() == Op_AbsL || u->Opcode() == Op_AbsI) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { + return u->Opcode() == Op_AbsD || u->Opcode() == Op_AbsF || + u->Opcode() == Op_AbsL || u->Opcode() == Op_AbsI; + }); } // Check for Max/Min(A, Max/Min(B, C)) where A == B or A == C if (use->is_MinMax()) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->is_MinMax()) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { return u->is_MinMax(); }); } auto enqueue_init_mem_projs = [&](ProjNode* proj) { add_users_to_worklist0(proj, worklist); @@ -2707,12 +2675,9 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ if (u->Opcode() == Op_LoadP && ut->isa_instptr()) { if (has_load_barrier_nodes) { // Search for load barriers behind the load - for (DUIterator_Fast i3max, i3 = u->fast_outs(i3max); i3 < i3max; i3++) { - Node* b = u->fast_out(i3); - if (bs->is_gc_barrier_node(b)) { - worklist.push(b); - } - } + add_users_to_worklist_if(worklist, u, [&](Node* b) { + return bs->is_gc_barrier_node(b); + }); } worklist.push(u); } @@ -2728,24 +2693,14 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ // VectorMaskToLongNode::Ideal_MaskAll looks through VectorStoreMask // to fold constant masks. if (use_op == Op_VectorStoreMask) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_VectorMaskToLong) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { return u->Opcode() == Op_VectorMaskToLong; }); } // From CastX2PNode::Ideal // CastX2P(AddX(x, y)) // CastX2P(SubX(x, y)) if (use->Opcode() == Op_AddX || use->Opcode() == Op_SubX) { - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == Op_CastX2P) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [](Node* u) { return u->Opcode() == Op_CastX2P; }); } /* AndNode has a special handling when one of the operands is a LShiftNode: @@ -2780,12 +2735,7 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ // e.g., (x - y) + y -> x; x + (y - x) -> y. if (use_op == Op_SubI || use_op == Op_SubL) { const int add_op = (use_op == Op_SubI) ? Op_AddI : Op_AddL; - for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) { - Node* u = use->fast_out(i2); - if (u->Opcode() == add_op) { - worklist.push(u); - } - } + add_users_to_worklist_if(worklist, use, [=](Node* u) { return u->Opcode() == add_op; }); } } @@ -2970,6 +2920,10 @@ void PhaseCCP::dump_type_and_node(const Node* n, const Type* t) { } #endif +bool PhaseCCP::not_bottom_type(Node* n) const { + return n->bottom_type() != type(n); +} + // We need to propagate the type change of 'n' to all its uses. Depending on the kind of node, additional nodes // (grandchildren or even further down) need to be revisited as their types could also be improved as a result // of the new type of 'n'. Push these nodes to the worklist. @@ -2982,7 +2936,7 @@ void PhaseCCP::push_child_nodes_to_worklist(Unique_Node_List& worklist, Node* n) } void PhaseCCP::push_if_not_bottom_type(Unique_Node_List& worklist, Node* n) const { - if (n->bottom_type() != type(n)) { + if (not_bottom_type(n)) { worklist.push(n); } } @@ -3005,9 +2959,9 @@ void PhaseCCP::push_more_uses(Unique_Node_List& worklist, Node* parent, const No // We must recheck Phis too if use is a Region. void PhaseCCP::push_phis(Unique_Node_List& worklist, const Node* use) const { if (use->is_Region()) { - for (DUIterator_Fast imax, i = use->fast_outs(imax); i < imax; i++) { - push_if_not_bottom_type(worklist, use->fast_out(i)); - } + add_users_to_worklist_if(worklist, use, [&](Node* u) { + return not_bottom_type(u); + }); } } @@ -3034,14 +2988,11 @@ void PhaseCCP::push_catch(Unique_Node_List& worklist, const Node* use) { void PhaseCCP::push_cmpu(Unique_Node_List& worklist, const Node* use) const { uint use_op = use->Opcode(); if (use_op == Op_AddI || use_op == Op_SubI) { - for (DUIterator_Fast imax, i = use->fast_outs(imax); i < imax; i++) { - Node* cmpu = use->fast_out(i); - const uint cmpu_opcode = cmpu->Opcode(); - if (cmpu_opcode == Op_CmpU || cmpu_opcode == Op_CmpU3) { - // Got a CmpU or CmpU3 which might need the new type information from node n. - push_if_not_bottom_type(worklist, cmpu); - } - } + // Got a CmpU or CmpU3 which might need the new type information from node n. + add_users_to_worklist_if(worklist, use, [&](Node* u) { + uint op = u->Opcode(); + return (op == Op_CmpU || op == Op_CmpU3) && not_bottom_type(u); + }); } } @@ -3130,12 +3081,9 @@ void PhaseCCP::push_loadp(Unique_Node_List& worklist, const Node* use) const { } void PhaseCCP::push_load_barrier(Unique_Node_List& worklist, const BarrierSetC2* barrier_set, const Node* use) { - for (DUIterator_Fast imax, i = use->fast_outs(imax); i < imax; i++) { - Node* barrier_node = use->fast_out(i); - if (barrier_set->is_gc_barrier_node(barrier_node)) { - worklist.push(barrier_node); - } - } + add_users_to_worklist_if(worklist, use, [&](Node* u) { + return barrier_set->is_gc_barrier_node(u); + }); } // AndI/L::Value() optimizes patterns similar to (v << 2) & 3, or CON & 3 to zero if they are bitwise disjoint. @@ -3171,12 +3119,9 @@ void PhaseCCP::push_and(Unique_Node_List& worklist, const Node* parent, const No void PhaseCCP::push_cast_ii(Unique_Node_List& worklist, const Node* parent, const Node* use) const { if (use->Opcode() == Op_CmpI && use->in(2) == parent) { Node* other_cmp_input = use->in(1); - for (DUIterator_Fast imax, i = other_cmp_input->fast_outs(imax); i < imax; i++) { - Node* cast_ii = other_cmp_input->fast_out(i); - if (cast_ii->is_CastII()) { - push_if_not_bottom_type(worklist, cast_ii); - } - } + add_users_to_worklist_if(worklist, other_cmp_input, [&](Node* u) { + return u->is_CastII() && not_bottom_type(u); + }); } } diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index cd38f37ccf5..94890c250c4 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -652,6 +652,7 @@ class PhaseCCP : public PhaseIterGVN { Node* fetch_next_node(Unique_Node_List& worklist); static void dump_type_and_node(const Node* n, const Type* t) PRODUCT_RETURN; + bool not_bottom_type(Node* n) const; void push_child_nodes_to_worklist(Unique_Node_List& worklist, Node* n) const; void push_if_not_bottom_type(Unique_Node_List& worklist, Node* n) const; void push_more_uses(Unique_Node_List& worklist, Node* parent, const Node* use) const; From 7c8f66c831e96d7ba6ffa0042130c556290761fc Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 4 Mar 2026 13:22:24 +0000 Subject: [PATCH 035/655] 8379041: Crash in ResolvedFieldEntry::assert_is_valid(): invalid put bytecode 0 Reviewed-by: matsaave, dholmes --- src/hotspot/share/oops/resolvedFieldEntry.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/oops/resolvedFieldEntry.cpp b/src/hotspot/share/oops/resolvedFieldEntry.cpp index 49e9115ca9a..122ecf092d8 100644 --- a/src/hotspot/share/oops/resolvedFieldEntry.cpp +++ b/src/hotspot/share/oops/resolvedFieldEntry.cpp @@ -77,10 +77,13 @@ void ResolvedFieldEntry::assert_is_valid() const { "field offset out of range %d >= %d", field_offset(), instanceOopDesc::base_offset_in_bytes()); assert(as_BasicType((TosState)tos_state()) != T_ILLEGAL, "tos_state is ILLEGAL"); assert(_flags < (1 << (max_flag_shift + 1)), "flags are too large %d", _flags); - assert((get_code() == 0 || get_code() == Bytecodes::_getstatic || get_code() == Bytecodes::_getfield), - "invalid get bytecode %d", get_code()); - assert((put_code() == 0 || put_code() == Bytecodes::_putstatic || put_code() == Bytecodes::_putfield), - "invalid put bytecode %d", put_code()); + + // Read each bytecode once. + volatile Bytecodes::Code g = (Bytecodes::Code)get_code(); + assert(g == 0 || g == Bytecodes::_getstatic || g == Bytecodes::_getfield, "invalid get bytecode %d", g); + + volatile Bytecodes::Code p = (Bytecodes::Code)put_code(); + assert(p == 0 || p == Bytecodes::_putstatic || p == Bytecodes::_putfield, "invalid put bytecode %d", p); } #endif From eb50630d9893970ed58034e878dfdc0ecf0961da Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 4 Mar 2026 13:57:22 +0000 Subject: [PATCH 036/655] 8379013: Remove some unused code in generateOopMap.cpp Reviewed-by: matsaave, dholmes --- src/hotspot/share/interpreter/oopMapCache.cpp | 28 +---------- src/hotspot/share/oops/generateOopMap.cpp | 50 ++----------------- src/hotspot/share/oops/generateOopMap.hpp | 41 ++------------- 3 files changed, 8 insertions(+), 111 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 29d6825d3e5..3769a473e3d 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,15 +78,10 @@ class OopMapForCacheEntry: public GenerateOopMap { int _stack_top; virtual bool report_results() const { return false; } - virtual bool possible_gc_point (BytecodeStream *bcs); - virtual void fill_stackmap_prolog (int nof_gc_points); - virtual void fill_stackmap_epilog (); virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stack_top); - virtual void fill_init_vars (GrowableArray *init_vars); - public: OopMapForCacheEntry(const methodHandle& method, int bci, OopMapCacheEntry *entry); @@ -119,27 +114,6 @@ bool OopMapForCacheEntry::compute_map(Thread* current) { return true; } - -bool OopMapForCacheEntry::possible_gc_point(BytecodeStream *bcs) { - return false; // We are not reporting any result. We call result_for_basicblock directly -} - - -void OopMapForCacheEntry::fill_stackmap_prolog(int nof_gc_points) { - // Do nothing -} - - -void OopMapForCacheEntry::fill_stackmap_epilog() { - // Do nothing -} - - -void OopMapForCacheEntry::fill_init_vars(GrowableArray *init_vars) { - // Do nothing -} - - void OopMapForCacheEntry::fill_stackmap_for_opcodes(BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index 97d8bf3d526..db1e8b4548b 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -391,7 +391,6 @@ void CellTypeState::print(outputStream *os) { // void GenerateOopMap::initialize_bb() { - _gc_points = 0; _bb_count = 0; _bb_hdr_bits.reinitialize(method()->code_size()); } @@ -409,7 +408,7 @@ void GenerateOopMap::bb_mark_fct(GenerateOopMap *c, int bci, int *data) { } -void GenerateOopMap::mark_bbheaders_and_count_gc_points() { +void GenerateOopMap::mark_bbheaders() { initialize_bb(); bool fellThrough = false; // False to get first BB marked. @@ -445,9 +444,6 @@ void GenerateOopMap::mark_bbheaders_and_count_gc_points() { default: break; } - - if (possible_gc_point(&bcs)) - _gc_points++; } } @@ -1051,9 +1047,6 @@ void GenerateOopMap::setup_method_entry_state() { // Initialize CellState type of arguments methodsig_to_effect(method()->signature(), method()->is_static(), vars()); - // If some references must be pre-assigned to null, then set that up - initialize_vars(); - // This is the start state merge_state_into_bb(&_basic_blocks[0]); @@ -1077,27 +1070,6 @@ void GenerateOopMap::update_basic_blocks(int bci, int delta, } } -// -// Initvars handling -// - -void GenerateOopMap::initialize_vars() { - for (int k = 0; k < _init_vars->length(); k++) - _state[_init_vars->at(k)] = CellTypeState::make_slot_ref(k); -} - -void GenerateOopMap::add_to_ref_init_set(int localNo) { - - if (TraceNewOopMapGeneration) - tty->print_cr("Added init vars: %d", localNo); - - // Is it already in the set? - if (_init_vars->contains(localNo) ) - return; - - _init_vars->append(localNo); -} - // // Interpreration code // @@ -1672,7 +1644,6 @@ void GenerateOopMap::ppload(CellTypeState *out, int loc_no) { if (vcts.can_be_uninit()) { // It is a ref-uninit conflict (at least). If there are other // problems, we'll get them in the next round - add_to_ref_init_set(loc_no); vcts = out1; } else { // It wasn't a ref-uninit conflict. So must be a @@ -2065,7 +2036,6 @@ GenerateOopMap::GenerateOopMap(const methodHandle& method) { // We have to initialize all variables here, that can be queried directly _method = method; _max_locals=0; - _init_vars = nullptr; #ifndef PRODUCT // If we are doing a detailed trace, include the regular trace information. @@ -2095,7 +2065,6 @@ bool GenerateOopMap::compute_map(Thread* current) { _max_stack = method()->max_stack(); _has_exceptions = (method()->has_exception_handler()); _nof_refval_conflicts = 0; - _init_vars = new GrowableArray(5); // There are seldom more than 5 init_vars _report_result = false; _report_result_for_send = false; _new_var_map = nullptr; @@ -2119,8 +2088,6 @@ bool GenerateOopMap::compute_map(Thread* current) { // if no code - do nothing // compiler needs info if (method()->code_size() == 0 || _max_locals + method()->max_stack() == 0) { - fill_stackmap_prolog(0); - fill_stackmap_epilog(); return true; } // Step 1: Compute all jump targets and their return value @@ -2129,7 +2096,7 @@ bool GenerateOopMap::compute_map(Thread* current) { // Step 2: Find all basic blocks and count GC points if (!_got_error) - mark_bbheaders_and_count_gc_points(); + mark_bbheaders(); // Step 3: Calculate stack maps if (!_got_error) @@ -2186,9 +2153,6 @@ void GenerateOopMap::report_result() { // We now want to report the result of the parse _report_result = true; - // Prolog code - fill_stackmap_prolog(_gc_points); - // Mark everything changed, then do one interpretation pass. for (int i = 0; i<_bb_count; i++) { if (_basic_blocks[i].is_reachable()) { @@ -2197,14 +2161,6 @@ void GenerateOopMap::report_result() { } } - // Note: Since we are skipping dead-code when we are reporting results, then - // the no. of encountered gc-points might be fewer than the previously number - // we have counted. (dead-code is a pain - it should be removed before we get here) - fill_stackmap_epilog(); - - // Report initvars - fill_init_vars(_init_vars); - _report_result = false; } diff --git a/src/hotspot/share/oops/generateOopMap.hpp b/src/hotspot/share/oops/generateOopMap.hpp index 0da3779d463..7c445887ee7 100644 --- a/src/hotspot/share/oops/generateOopMap.hpp +++ b/src/hotspot/share/oops/generateOopMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -348,17 +348,15 @@ class GenerateOopMap { // Basicblock info BasicBlock * _basic_blocks; // Array of basicblock info - int _gc_points; int _bb_count; ResourceBitMap _bb_hdr_bits; // Basicblocks methods void initialize_bb (); - void mark_bbheaders_and_count_gc_points(); + void mark_bbheaders(); bool is_bb_header (int bci) const { return _bb_hdr_bits.at(bci); } - int gc_points () const { return _gc_points; } int bb_count () const { return _bb_count; } void set_bbmark_bit (int bci); BasicBlock * get_basic_block_at (int bci) const; @@ -419,12 +417,6 @@ class GenerateOopMap { void report_result (); - // Initvars - GrowableArray * _init_vars; - - void initialize_vars (); - void add_to_ref_init_set (int localNo); - // Conflicts rewrite logic bool _conflict; // True, if a conflict occurred during interpretation int _nof_refval_conflicts; // No. of conflicts that require rewrites @@ -450,7 +442,7 @@ class GenerateOopMap { int binsToHold (int no) { return ((no+(BitsPerWord-1))/BitsPerWord); } char *state_vec_to_string (CellTypeState* vec, int len); - // Helper method. Can be used in subclasses to fx. calculate gc_points. If the current instruction + // Helper method. If the current instruction // is a control transfer, then calls the jmpFct all possible destinations. void ret_jump_targets_do (BytecodeStream *bcs, jmpFct_t jmpFct, int varNo,int *data); bool jump_targets_do (BytecodeStream *bcs, jmpFct_t jmpFct, int *data); @@ -480,14 +472,7 @@ class GenerateOopMap { bool monitor_safe() { return _monitor_safe; } // Specialization methods. Intended use: - // - possible_gc_point must return true for every bci for which the stackmaps must be returned - // - fill_stackmap_prolog is called just before the result is reported. The arguments tells the estimated - // number of gc points // - fill_stackmap_for_opcodes is called once for each bytecode index in order (0...code_length-1) - // - fill_stackmap_epilog is called after all results has been reported. Note: Since the algorithm does not report - // stackmaps for deadcode, fewer gc_points might have been encountered than assumed during the epilog. It is the - // responsibility of the subclass to count the correct number. - // - fill_init_vars are called once with the result of the init_vars computation // // All these methods are used during a call to: compute_map. Note: Non of the return results are valid // after compute_map returns, since all values are allocated as resource objects. @@ -495,15 +480,10 @@ class GenerateOopMap { // All virtual method must be implemented in subclasses virtual bool allow_rewrites () const { return false; } virtual bool report_results () const { return true; } - virtual bool report_init_vars () const { return true; } - virtual bool possible_gc_point (BytecodeStream *bcs) { ShouldNotReachHere(); return false; } - virtual void fill_stackmap_prolog (int nof_gc_points) { ShouldNotReachHere(); } - virtual void fill_stackmap_epilog () { ShouldNotReachHere(); } virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stackTop) { ShouldNotReachHere(); } - virtual void fill_init_vars (GrowableArray *init_vars) { ShouldNotReachHere();; } }; // @@ -513,19 +493,12 @@ class GenerateOopMap { class ResolveOopMapConflicts: public GenerateOopMap { private: - bool _must_clear_locals; - virtual bool report_results() const { return false; } - virtual bool report_init_vars() const { return true; } virtual bool allow_rewrites() const { return true; } - virtual bool possible_gc_point (BytecodeStream *bcs) { return false; } - virtual void fill_stackmap_prolog (int nof_gc_points) {} - virtual void fill_stackmap_epilog () {} virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stack_top) {} - virtual void fill_init_vars (GrowableArray *init_vars) { _must_clear_locals = init_vars->length() > 0; } #ifndef PRODUCT // Statistics @@ -535,10 +508,9 @@ class ResolveOopMapConflicts: public GenerateOopMap { #endif public: - ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { _must_clear_locals = false; }; + ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { } methodHandle do_potential_rewrite(TRAPS); - bool must_clear_locals() const { return _must_clear_locals; } }; @@ -549,16 +521,11 @@ class GeneratePairingInfo: public GenerateOopMap { private: virtual bool report_results() const { return false; } - virtual bool report_init_vars() const { return false; } virtual bool allow_rewrites() const { return false; } - virtual bool possible_gc_point (BytecodeStream *bcs) { return false; } - virtual void fill_stackmap_prolog (int nof_gc_points) {} - virtual void fill_stackmap_epilog () {} virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stack_top) {} - virtual void fill_init_vars (GrowableArray *init_vars) {} public: GeneratePairingInfo(const methodHandle& method) : GenerateOopMap(method) {}; From 3531c78dea58f1c33752685bd1a876162ec03825 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Wed, 4 Mar 2026 14:30:31 +0000 Subject: [PATCH 037/655] 8379196: delta apply fix for JDK-8214934 Reviewed-by: jlahoda --- .../com/sun/tools/javac/comp/TransTypes.java | 24 +-- .../IncorrectCastOffsetTest.java | 175 ------------------ 2 files changed, 5 insertions(+), 194 deletions(-) delete mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index 1229939c0bf..862c02ea5f0 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -29,6 +29,7 @@ package com.sun.tools.javac.comp; import com.sun.source.tree.MemberReferenceTree.ReferenceMode; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Attribute.TypeCompound; +import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.TypeVar; import com.sun.tools.javac.jvm.Target; @@ -48,6 +49,8 @@ import static com.sun.tools.javac.code.TypeTag.VOID; import static com.sun.tools.javac.comp.CompileStates.CompileState; import com.sun.tools.javac.tree.JCTree.JCBreak; +import javax.lang.model.type.TypeKind; + /** This pass translates Generic Java to conventional Java. * *

This is NOT part of any supported API. @@ -106,9 +109,7 @@ public class TransTypes extends TreeTranslator { if (!types.isSameType(tree.type, target)) { if (!resolve.isAccessible(env, target.tsym)) resolve.logAccessErrorInternal(env, tree, target); - tree = explicitCastTP != null && types.isSameType(target, explicitCastTP) ? - tree : - make.TypeCast(make.Type(target), tree).setType(target); + tree = make.TypeCast(make.Type(target), tree).setType(target); } make.pos = oldpos; return tree; @@ -439,29 +440,16 @@ public class TransTypes extends TreeTranslator { /** Visitor argument: proto-type. */ private Type pt; - /** we use this type to indicate that "upstream" there is an explicit cast to this type, - * this way we can avoid generating redundant type casts. Redundant casts are not - * innocuous as they can trump user provided ones and affect the offset - * calculation of type annotations applied to the user provided type cast. - */ - private Type explicitCastTP; /** Visitor method: perform a type translation on tree. */ public T translate(T tree, Type pt) { - return translate(tree, pt, pt == explicitCastTP ? explicitCastTP : null); - } - - public T translate(T tree, Type pt, Type castTP) { Type prevPt = this.pt; - Type prevCastPT = this.explicitCastTP; try { this.pt = pt; - this.explicitCastTP = castTP; return translate(tree); } finally { this.pt = prevPt; - this.explicitCastTP = prevCastPT; } } @@ -1049,9 +1037,7 @@ public class TransTypes extends TreeTranslator { tree.clazz = translate(tree.clazz, null); Type originalTarget = tree.type; tree.type = erasure(tree.type); - JCExpression newExpression = tree.clazz.hasTag(Tag.ANNOTATED_TYPE) ? - translate(tree.expr, tree.type, tree.type) : - translate(tree.expr, tree.type); + JCExpression newExpression = translate(tree.expr, tree.type); if (newExpression != tree.expr) { JCTypeCast typeCast = newExpression.hasTag(Tag.TYPECAST) ? (JCTypeCast) newExpression diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java deleted file mode 100644 index f679926bcf4..00000000000 --- a/test/langtools/tools/javac/annotations/typeAnnotations/IncorrectCastOffsetTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8214934 - * @summary Wrong type annotation offset on casts on expressions - * @library /tools/lib - * @modules jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.main - * jdk.jdeps/com.sun.tools.javap - * @build toolbox.ToolBox toolbox.JavapTask - * @run compile IncorrectCastOffsetTest.java - * @run main IncorrectCastOffsetTest - */ - -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import java.nio.file.Path; -import java.nio.file.Paths; - -import java.util.List; - -import toolbox.JavapTask; -import toolbox.Task; -import toolbox.ToolBox; - -public class IncorrectCastOffsetTest { - @Target(ElementType.TYPE_USE) - @Retention(RetentionPolicy.RUNTIME) - @interface TypeUse {} - - @Target(ElementType.TYPE_USE) - @Retention(RetentionPolicy.RUNTIME) - @interface TypeUse2 {} - - class AnnotatedCast1 { - private static String checkcast(boolean test, Object obj, Object obj2) { - return (@TypeUse String)(test ? obj : obj2); - } - } - - class AnnotatedCast2 { - private static String checkcast(Object obj) { - return (@TypeUse String)(obj); - } - } - - class AnnotatedCast3 { - private static String checkcast(boolean test, Object obj, Object obj2) { - return (@TypeUse @TypeUse2 String)(test ? obj : obj2); - } - } - - class AnnotatedCast4 { - private static String checkcast(Object obj) { - return (@TypeUse String)(@TypeUse2 CharSequence)(obj); - } - } - - ToolBox tb; - - IncorrectCastOffsetTest() { - tb = new ToolBox(); - } - - public static void main(String args[]) { - IncorrectCastOffsetTest incorrectCastOffsetTest = new IncorrectCastOffsetTest(); - incorrectCastOffsetTest.run(); - } - - void run() { - test("IncorrectCastOffsetTest$AnnotatedCast1.class", - /* - * generated code: - * 0: iload_0 - * 1: ifeq 8 - * 4: aload_1 - * 5: goto 9 - * 8: aload_2 - * 9: checkcast #13 // class java/lang/String - * 12: areturn - */ - List.of( - "RuntimeVisibleTypeAnnotations:", - "0: #35(): CAST, offset=9, type_index=0" - ) - ); - test("IncorrectCastOffsetTest$AnnotatedCast2.class", - /* - * generated code: - * 0: aload_0 - * 1: checkcast #13 // class java/lang/String - * 4: areturn - */ - List.of( - "RuntimeVisibleTypeAnnotations:", - "0: #31(): CAST, offset=1, type_index=0" - ) - ); - test("IncorrectCastOffsetTest$AnnotatedCast3.class", - /* - * generated code: - * 0: iload_0 - * 1: ifeq 8 - * 4: aload_1 - * 5: goto 9 - * 8: aload_2 - * 9: checkcast #13 // class java/lang/String - * 12: areturn - */ - List.of( - "RuntimeVisibleTypeAnnotations:", - "0: #35(): CAST, offset=9, type_index=0", - "IncorrectCastOffsetTest$TypeUse", - "1: #36(): CAST, offset=9, type_index=0", - "IncorrectCastOffsetTest$TypeUse2" - ) - ); - test("IncorrectCastOffsetTest$AnnotatedCast4.class", - /* - * generated code: - * 0: aload_0 - * 1: checkcast #13 // class java/lang/CharSequence - * 4: checkcast #15 // class java/lang/String - * 7: areturn - */ - List.of( - "RuntimeVisibleTypeAnnotations:", - "0: #33(): CAST, offset=4, type_index=0", - "IncorrectCastOffsetTest$TypeUse", - "#34(): CAST, offset=1, type_index=0", - "IncorrectCastOffsetTest$TypeUse2" - ) - ); - } - - void test(String clazz, List expectedOutput) { - Path pathToClass = Paths.get(ToolBox.testClasses, clazz); - String javapOut = new JavapTask(tb) - .options("-v", "-p") - .classes(pathToClass.toString()) - .run() - .getOutput(Task.OutputKind.DIRECT); - - for (String expected : expectedOutput) { - if (!javapOut.contains(expected)) - throw new AssertionError("unexpected output"); - } - } - -} From 4d2c537189cba77d3bbfab36ca3e1c3ceb7c603f Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 4 Mar 2026 17:16:32 +0000 Subject: [PATCH 038/655] 8378992: Case folding cache should not look up code point U+0000 Reviewed-by: sherman, rriggs --- .../classes/jdk/internal/lang/CaseFolding.java.template | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template index 24a183c8da0..24f48151f21 100644 --- a/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template +++ b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,6 +188,12 @@ public final class CaseFolding { } private static long getDefined(int cp) { + // Exclude code point U+0000, which is guaranteed to have no + // case-folding mapping. + if (cp == 0) { + return -1; + } + var hashes = CASE_FOLDING_HASHES; var length = CASE_FOLDING_CPS.length; // hashed based on total defined. var hash = cp % length; From 8b91537f109b22333c6008ba64cada9711534cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Wed, 4 Mar 2026 17:17:31 +0000 Subject: [PATCH 039/655] 8379203: [BACKOUT] Remove some unused code in generateOopMap.cpp Reviewed-by: liach, coleenp --- src/hotspot/share/interpreter/oopMapCache.cpp | 28 ++++++++++- src/hotspot/share/oops/generateOopMap.cpp | 50 +++++++++++++++++-- src/hotspot/share/oops/generateOopMap.hpp | 41 +++++++++++++-- 3 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 3769a473e3d..29d6825d3e5 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,10 +78,15 @@ class OopMapForCacheEntry: public GenerateOopMap { int _stack_top; virtual bool report_results() const { return false; } + virtual bool possible_gc_point (BytecodeStream *bcs); + virtual void fill_stackmap_prolog (int nof_gc_points); + virtual void fill_stackmap_epilog (); virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stack_top); + virtual void fill_init_vars (GrowableArray *init_vars); + public: OopMapForCacheEntry(const methodHandle& method, int bci, OopMapCacheEntry *entry); @@ -114,6 +119,27 @@ bool OopMapForCacheEntry::compute_map(Thread* current) { return true; } + +bool OopMapForCacheEntry::possible_gc_point(BytecodeStream *bcs) { + return false; // We are not reporting any result. We call result_for_basicblock directly +} + + +void OopMapForCacheEntry::fill_stackmap_prolog(int nof_gc_points) { + // Do nothing +} + + +void OopMapForCacheEntry::fill_stackmap_epilog() { + // Do nothing +} + + +void OopMapForCacheEntry::fill_init_vars(GrowableArray *init_vars) { + // Do nothing +} + + void OopMapForCacheEntry::fill_stackmap_for_opcodes(BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index db1e8b4548b..97d8bf3d526 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -391,6 +391,7 @@ void CellTypeState::print(outputStream *os) { // void GenerateOopMap::initialize_bb() { + _gc_points = 0; _bb_count = 0; _bb_hdr_bits.reinitialize(method()->code_size()); } @@ -408,7 +409,7 @@ void GenerateOopMap::bb_mark_fct(GenerateOopMap *c, int bci, int *data) { } -void GenerateOopMap::mark_bbheaders() { +void GenerateOopMap::mark_bbheaders_and_count_gc_points() { initialize_bb(); bool fellThrough = false; // False to get first BB marked. @@ -444,6 +445,9 @@ void GenerateOopMap::mark_bbheaders() { default: break; } + + if (possible_gc_point(&bcs)) + _gc_points++; } } @@ -1047,6 +1051,9 @@ void GenerateOopMap::setup_method_entry_state() { // Initialize CellState type of arguments methodsig_to_effect(method()->signature(), method()->is_static(), vars()); + // If some references must be pre-assigned to null, then set that up + initialize_vars(); + // This is the start state merge_state_into_bb(&_basic_blocks[0]); @@ -1070,6 +1077,27 @@ void GenerateOopMap::update_basic_blocks(int bci, int delta, } } +// +// Initvars handling +// + +void GenerateOopMap::initialize_vars() { + for (int k = 0; k < _init_vars->length(); k++) + _state[_init_vars->at(k)] = CellTypeState::make_slot_ref(k); +} + +void GenerateOopMap::add_to_ref_init_set(int localNo) { + + if (TraceNewOopMapGeneration) + tty->print_cr("Added init vars: %d", localNo); + + // Is it already in the set? + if (_init_vars->contains(localNo) ) + return; + + _init_vars->append(localNo); +} + // // Interpreration code // @@ -1644,6 +1672,7 @@ void GenerateOopMap::ppload(CellTypeState *out, int loc_no) { if (vcts.can_be_uninit()) { // It is a ref-uninit conflict (at least). If there are other // problems, we'll get them in the next round + add_to_ref_init_set(loc_no); vcts = out1; } else { // It wasn't a ref-uninit conflict. So must be a @@ -2036,6 +2065,7 @@ GenerateOopMap::GenerateOopMap(const methodHandle& method) { // We have to initialize all variables here, that can be queried directly _method = method; _max_locals=0; + _init_vars = nullptr; #ifndef PRODUCT // If we are doing a detailed trace, include the regular trace information. @@ -2065,6 +2095,7 @@ bool GenerateOopMap::compute_map(Thread* current) { _max_stack = method()->max_stack(); _has_exceptions = (method()->has_exception_handler()); _nof_refval_conflicts = 0; + _init_vars = new GrowableArray(5); // There are seldom more than 5 init_vars _report_result = false; _report_result_for_send = false; _new_var_map = nullptr; @@ -2088,6 +2119,8 @@ bool GenerateOopMap::compute_map(Thread* current) { // if no code - do nothing // compiler needs info if (method()->code_size() == 0 || _max_locals + method()->max_stack() == 0) { + fill_stackmap_prolog(0); + fill_stackmap_epilog(); return true; } // Step 1: Compute all jump targets and their return value @@ -2096,7 +2129,7 @@ bool GenerateOopMap::compute_map(Thread* current) { // Step 2: Find all basic blocks and count GC points if (!_got_error) - mark_bbheaders(); + mark_bbheaders_and_count_gc_points(); // Step 3: Calculate stack maps if (!_got_error) @@ -2153,6 +2186,9 @@ void GenerateOopMap::report_result() { // We now want to report the result of the parse _report_result = true; + // Prolog code + fill_stackmap_prolog(_gc_points); + // Mark everything changed, then do one interpretation pass. for (int i = 0; i<_bb_count; i++) { if (_basic_blocks[i].is_reachable()) { @@ -2161,6 +2197,14 @@ void GenerateOopMap::report_result() { } } + // Note: Since we are skipping dead-code when we are reporting results, then + // the no. of encountered gc-points might be fewer than the previously number + // we have counted. (dead-code is a pain - it should be removed before we get here) + fill_stackmap_epilog(); + + // Report initvars + fill_init_vars(_init_vars); + _report_result = false; } diff --git a/src/hotspot/share/oops/generateOopMap.hpp b/src/hotspot/share/oops/generateOopMap.hpp index 7c445887ee7..0da3779d463 100644 --- a/src/hotspot/share/oops/generateOopMap.hpp +++ b/src/hotspot/share/oops/generateOopMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -348,15 +348,17 @@ class GenerateOopMap { // Basicblock info BasicBlock * _basic_blocks; // Array of basicblock info + int _gc_points; int _bb_count; ResourceBitMap _bb_hdr_bits; // Basicblocks methods void initialize_bb (); - void mark_bbheaders(); + void mark_bbheaders_and_count_gc_points(); bool is_bb_header (int bci) const { return _bb_hdr_bits.at(bci); } + int gc_points () const { return _gc_points; } int bb_count () const { return _bb_count; } void set_bbmark_bit (int bci); BasicBlock * get_basic_block_at (int bci) const; @@ -417,6 +419,12 @@ class GenerateOopMap { void report_result (); + // Initvars + GrowableArray * _init_vars; + + void initialize_vars (); + void add_to_ref_init_set (int localNo); + // Conflicts rewrite logic bool _conflict; // True, if a conflict occurred during interpretation int _nof_refval_conflicts; // No. of conflicts that require rewrites @@ -442,7 +450,7 @@ class GenerateOopMap { int binsToHold (int no) { return ((no+(BitsPerWord-1))/BitsPerWord); } char *state_vec_to_string (CellTypeState* vec, int len); - // Helper method. If the current instruction + // Helper method. Can be used in subclasses to fx. calculate gc_points. If the current instruction // is a control transfer, then calls the jmpFct all possible destinations. void ret_jump_targets_do (BytecodeStream *bcs, jmpFct_t jmpFct, int varNo,int *data); bool jump_targets_do (BytecodeStream *bcs, jmpFct_t jmpFct, int *data); @@ -472,7 +480,14 @@ class GenerateOopMap { bool monitor_safe() { return _monitor_safe; } // Specialization methods. Intended use: + // - possible_gc_point must return true for every bci for which the stackmaps must be returned + // - fill_stackmap_prolog is called just before the result is reported. The arguments tells the estimated + // number of gc points // - fill_stackmap_for_opcodes is called once for each bytecode index in order (0...code_length-1) + // - fill_stackmap_epilog is called after all results has been reported. Note: Since the algorithm does not report + // stackmaps for deadcode, fewer gc_points might have been encountered than assumed during the epilog. It is the + // responsibility of the subclass to count the correct number. + // - fill_init_vars are called once with the result of the init_vars computation // // All these methods are used during a call to: compute_map. Note: Non of the return results are valid // after compute_map returns, since all values are allocated as resource objects. @@ -480,10 +495,15 @@ class GenerateOopMap { // All virtual method must be implemented in subclasses virtual bool allow_rewrites () const { return false; } virtual bool report_results () const { return true; } + virtual bool report_init_vars () const { return true; } + virtual bool possible_gc_point (BytecodeStream *bcs) { ShouldNotReachHere(); return false; } + virtual void fill_stackmap_prolog (int nof_gc_points) { ShouldNotReachHere(); } + virtual void fill_stackmap_epilog () { ShouldNotReachHere(); } virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stackTop) { ShouldNotReachHere(); } + virtual void fill_init_vars (GrowableArray *init_vars) { ShouldNotReachHere();; } }; // @@ -493,12 +513,19 @@ class GenerateOopMap { class ResolveOopMapConflicts: public GenerateOopMap { private: + bool _must_clear_locals; + virtual bool report_results() const { return false; } + virtual bool report_init_vars() const { return true; } virtual bool allow_rewrites() const { return true; } + virtual bool possible_gc_point (BytecodeStream *bcs) { return false; } + virtual void fill_stackmap_prolog (int nof_gc_points) {} + virtual void fill_stackmap_epilog () {} virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stack_top) {} + virtual void fill_init_vars (GrowableArray *init_vars) { _must_clear_locals = init_vars->length() > 0; } #ifndef PRODUCT // Statistics @@ -508,9 +535,10 @@ class ResolveOopMapConflicts: public GenerateOopMap { #endif public: - ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { } + ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { _must_clear_locals = false; }; methodHandle do_potential_rewrite(TRAPS); + bool must_clear_locals() const { return _must_clear_locals; } }; @@ -521,11 +549,16 @@ class GeneratePairingInfo: public GenerateOopMap { private: virtual bool report_results() const { return false; } + virtual bool report_init_vars() const { return false; } virtual bool allow_rewrites() const { return false; } + virtual bool possible_gc_point (BytecodeStream *bcs) { return false; } + virtual void fill_stackmap_prolog (int nof_gc_points) {} + virtual void fill_stackmap_epilog () {} virtual void fill_stackmap_for_opcodes (BytecodeStream *bcs, CellTypeState* vars, CellTypeState* stack, int stack_top) {} + virtual void fill_init_vars (GrowableArray *init_vars) {} public: GeneratePairingInfo(const methodHandle& method) : GenerateOopMap(method) {}; From 0fbf58d8ff4fae370d5a839e59cebf713a1f1e5a Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 4 Mar 2026 17:33:32 +0000 Subject: [PATCH 040/655] 8372353: API to compute the byte length of a String encoded in a given Charset Reviewed-by: rriggs, naoto, vyazici --- .../share/classes/java/lang/String.java | 95 +++++++++++++- test/jdk/java/lang/String/Encodings.java | 8 +- test/jdk/java/lang/String/Exceptions.java | 13 +- test/jdk/sun/nio/cs/TestStringCoding.java | 10 +- .../lang/foreign/StringLoopJmhBenchmark.java | 122 ++++++++++++++++++ 5 files changed, 235 insertions(+), 13 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/foreign/StringLoopJmhBenchmark.java diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index fc05febdb45..c6c08ed4473 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -1133,6 +1133,34 @@ public final class String return Arrays.copyOf(dst, dp); } + // This follows the implementation of encodeASCII and encode8859_1 + private static int encodedLengthASCIIor8859_1(byte coder, byte[] val) { + if (coder == LATIN1) { + return val.length; + } + int len = val.length >> 1; + int dp = 0; + int sp = 0; + int sl = len; + while (sp < sl) { + char c = StringUTF16.getChar(val, sp); + if (c >= Character.MIN_HIGH_SURROGATE) { + break; + } + dp++; + sp++; + } + while (sp < sl) { + char c = StringUTF16.getChar(val, sp++); + if (Character.isHighSurrogate(c) && sp < sl && + Character.isLowSurrogate(StringUTF16.getChar(val, sp))) { + sp++; + } + dp++; + } + return dp; + } + //------------------------------ utf8 ------------------------------------ /** @@ -1467,6 +1495,27 @@ public final class String return Arrays.copyOf(dst, dp); } + // This follows the implementation of encodeUTF8 + private static int encodedLengthUTF8(byte coder, byte[] val) { + if (coder == UTF16) { + return encodedLengthUTF8_UTF16(val, null); + } + int positives = StringCoding.countPositives(val, 0, val.length); + if (positives == val.length) { + return positives; + } + int dp = positives; + for (int i = dp; i < val.length; i++) { + byte c = val[i]; + if (c < 0) { + dp += 2; + } else { + dp++; + } + } + return dp; + } + /** * {@return the byte array obtained by first decoding {@code val} with * UTF-16, and then encoding the result with UTF-8} @@ -1484,11 +1533,8 @@ public final class String int sl = val.length >> 1; // UTF-8 encoded can be as much as 3 times the string length // For very large estimate, (as in overflow of 32 bit int), precompute the exact size - long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, exClass) : sl * 3; - if (allocLen > (long)Integer.MAX_VALUE) { - throw new OutOfMemoryError("Required length exceeds implementation limit"); - } - byte[] dst = new byte[(int) allocLen]; + int allocLen = (sl * 3 < 0) ? encodedLengthUTF8_UTF16(val, exClass) : sl * 3; + byte[] dst = new byte[allocLen]; while (sp < sl) { // ascii fast loop; char c = StringUTF16.getChar(val, sp); @@ -1547,11 +1593,20 @@ public final class String * @param The exception type parameter to enable callers to avoid * having to declare the exception */ - private static long computeSizeUTF8_UTF16(byte[] val, Class exClass) throws E { + private static int encodedLengthUTF8_UTF16(byte[] val, Class exClass) throws E { long dp = 0L; int sp = 0; int sl = val.length >> 1; + while (sp < sl) { + // ascii fast loop; + char c = StringUTF16.getChar(val, sp); + if (c >= '\u0080') { + break; + } + dp++; + sp++; + } while (sp < sl) { char c = StringUTF16.getChar(val, sp++); if (c < 0x80) { @@ -1580,7 +1635,10 @@ public final class String dp += 3; } } - return dp; + if (dp > (long)Integer.MAX_VALUE) { + throw new OutOfMemoryError("Required length exceeds implementation limit"); + } + return (int) dp; } /** @@ -2045,6 +2103,29 @@ public final class String return encode(Charset.defaultCharset(), coder(), value); } + /** + * {@return the length in bytes of this {@code String} encoded with the given {@link Charset}} + * + *

The returned length accounts for the replacement of malformed-input and unmappable-character + * sequences with the charset's default replacement byte array. The result will be the same value + * as {@link #getBytes(Charset) getBytes(cs).length}. + * + * @apiNote This method provides equivalent or better performance than {@link #getBytes(Charset) + * getBytes(cs).length}. + * + * @param cs The {@link Charset} used to the compute the length + * @since 27 + */ + public int encodedLength(Charset cs) { + Objects.requireNonNull(cs); + if (cs == UTF_8.INSTANCE) { + return encodedLengthUTF8(coder, value); + } else if (cs == ISO_8859_1.INSTANCE || cs == US_ASCII.INSTANCE) { + return encodedLengthASCIIor8859_1(coder, value); + } + return getBytes(cs).length; + } + boolean bytesCompatible(Charset charset, int srcIndex, int numChars) { if (isLatin1()) { if (charset == ISO_8859_1.INSTANCE) { diff --git a/test/jdk/java/lang/String/Encodings.java b/test/jdk/java/lang/String/Encodings.java index 4714815026e..7974157ede0 100644 --- a/test/jdk/java/lang/String/Encodings.java +++ b/test/jdk/java/lang/String/Encodings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 4085160 4139951 5005831 + * @bug 4085160 4139951 5005831 8372353 * @summary Test that required character encodings are supported */ @@ -106,6 +106,10 @@ public class Encodings { if (!equals(bs, bytes)) throw new Exception(charset + ": String.getBytes failed"); + /* String.encodedLength(Charset charset) */ + if (bs.length != str.encodedLength(charset)) + throw new Exception(charset + ": String.encodedLength failed"); + // Calls to String.getBytes(Charset) shouldn't automatically // use the cached thread-local encoder. if (charset.name().equals("UTF-16BE")) { diff --git a/test/jdk/java/lang/String/Exceptions.java b/test/jdk/java/lang/String/Exceptions.java index 3ba7792f424..15ffe3eac20 100644 --- a/test/jdk/java/lang/String/Exceptions.java +++ b/test/jdk/java/lang/String/Exceptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 4472841 4703640 4705681 4705683 4833095 5005831 + * @bug 4472841 4703640 4705681 4705683 4833095 5005831 8372353 * @summary Verify that constructor exceptions are thrown as expected. */ @@ -397,6 +397,14 @@ public class Exceptions { }}); } + private static void encodedLength() { + System.out.println("encodedLength(Charset charset)"); + tryCatch(" null", NullPointerException.class, new Runnable() { + public void run() { + "foo".encodedLength((Charset)null); + }}); + } + private static void contentEquals() { System.out.println("contentEquals(StringBuffer sb)"); tryCatch(" null", NullPointerException.class, new Runnable() { @@ -640,6 +648,7 @@ public class Exceptions { // getBytes(Locale) // getBytes(String) // getBytes(Charset) + encodedLength(); // encodedLength(Charset) contentEquals(); // contentEquals(StringBuffer) compareTo(); // compareTo(String), compareTo(Object) compareToIgnoreCase();// compareToIgnoreCase(String) diff --git a/test/jdk/sun/nio/cs/TestStringCoding.java b/test/jdk/sun/nio/cs/TestStringCoding.java index d708ef180a2..b81ffb07d20 100644 --- a/test/jdk/sun/nio/cs/TestStringCoding.java +++ b/test/jdk/sun/nio/cs/TestStringCoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 6636323 6636319 7040220 7096080 7183053 8080248 8054307 + * @bug 6636323 6636319 7040220 7096080 7183053 8080248 8054307 8372353 * @summary Test if StringCoding and NIO result have the same de/encoding result * @library /test/lib * @modules java.base/sun.nio.cs @@ -169,6 +169,12 @@ public class TestStringCoding { if (!Arrays.equals(baSC, baNIO)) { throw new RuntimeException("getBytes(cs) failed -> " + cs.name()); } + //encodedLength(cs); + int encodedLength = str.encodedLength(cs); + if (baSC.length != encodedLength) { + throw new RuntimeException(String.format("encodedLength failed (%d != %d) -> %s", + baSC.length, encodedLength, cs.name())); + } return baSC; } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/StringLoopJmhBenchmark.java b/test/micro/org/openjdk/bench/java/lang/foreign/StringLoopJmhBenchmark.java new file mode 100644 index 00000000000..1733b73886e --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/StringLoopJmhBenchmark.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2026, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.foreign; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.annotations.State; + +@Warmup(time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +@State(Scope.Benchmark) +public class StringLoopJmhBenchmark { + @Param({"10", "100", "1000", "100000"}) + int stringLength; + + @Param({"ASCII", "LATIN1", "UTF16"}) + String encoding; + + String stringData; + + @Setup + public void setUp() { + stringData = ""; + + // Character at the _end_ to affect if we hit + // - ASCII = compact strings and compatible with UTF-8 + // - LATIN1 = compact strings but not compatible with UTF-8 + // - UTF16 = 2-byte char storage and not compatible with UTF-8 + String c; + if (encoding.equals("ASCII")) { + c = "a"; + } else if (encoding.equals("LATIN1")) { + c = "\u00C4"; + } else if (encoding.equals("UTF16")) { + c = "\u2603"; + } else { + throw new IllegalArgumentException("Unknown encoding: " + encoding); + } + + var stringDataBuilder = new StringBuilder(stringLength + 1); + while (stringDataBuilder.length() < stringLength) { + stringDataBuilder.append((char) (Math.random() * 26) + 'a'); + } + stringData = stringDataBuilder.append(c).toString(); + } + + @Benchmark + public int utf8LenByLoop() { + final String s = stringData; + final int len = s.length(); + + // ASCII prefix strings. + int idx = 0; + for (char c; idx < len && (c = s.charAt(idx)) < 0x80; ++idx) {} + + // Entire string was ASCII. + if (idx == len) { + return len; + } + + int utf8Len = len; + for (char c; idx < len; ++idx) { + c = s.charAt(idx); + if (c < 0x80) { + utf8Len++; + } else if (c < 0x800) { + utf8Len += 2; + } else { + utf8Len += 3; + if (Character.isSurrogate(c)) { + int cp = Character.codePointAt(s, idx); + if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + throw new RuntimeException("Unpaired surrogate"); + } + idx++; + } + } + } + return utf8Len; + } + + @Benchmark + public int getBytes() throws Exception { + return stringData.getBytes(StandardCharsets.UTF_8).length; + } + + @Benchmark + public int encodedLength() throws Exception { + return stringData.encodedLength(StandardCharsets.UTF_8); + } +} From c52d7b7cbc89548c3e9cd68a29ff0cec04888b09 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 4 Mar 2026 18:50:13 +0000 Subject: [PATCH 041/655] 8378878: Refactor java/nio/channels/AsynchronousSocketChannel test to use JUnit Reviewed-by: alanb --- .../CompletionHandlerRelease.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/test/jdk/java/nio/channels/AsynchronousSocketChannel/CompletionHandlerRelease.java b/test/jdk/java/nio/channels/AsynchronousSocketChannel/CompletionHandlerRelease.java index 7abbf064b40..962d7728a55 100644 --- a/test/jdk/java/nio/channels/AsynchronousSocketChannel/CompletionHandlerRelease.java +++ b/test/jdk/java/nio/channels/AsynchronousSocketChannel/CompletionHandlerRelease.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* @test * @bug 8202252 - * @run testng CompletionHandlerRelease + * @run junit CompletionHandlerRelease * @summary Verify that reference to CompletionHandler is cleared after use */ @@ -44,10 +44,12 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; public class CompletionHandlerRelease { @Test @@ -132,16 +134,16 @@ public class CompletionHandlerRelease { } } - private AsynchronousChannelGroup GROUP; + private static AsynchronousChannelGroup GROUP; - @BeforeTest - void setup() throws IOException { + @BeforeAll + static void setup() throws IOException { GROUP = AsynchronousChannelGroup.withFixedThreadPool(2, Executors.defaultThreadFactory()); } - @AfterTest - void cleanup() throws IOException { + @AfterAll + static void cleanup() throws IOException { GROUP.shutdownNow(); } @@ -199,13 +201,13 @@ public class CompletionHandlerRelease { } } - private void waitForRefToClear(Reference ref, ReferenceQueue queue) + private static void waitForRefToClear(Reference ref, ReferenceQueue queue) throws InterruptedException { Reference r; while ((r = queue.remove(20)) == null) { System.gc(); } - assertEquals(r, ref); + assertSame(ref, r); assertNull(r.get()); } } From 9d1d0c6f0553c5f042351d1def385589015fefd6 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 4 Mar 2026 19:46:06 +0000 Subject: [PATCH 042/655] 8379166: Upstream redundant diffs fixed in Valhalla - Part 1 Reviewed-by: rriggs --- .../classes/java/io/ObjectInputStream.java | 2 +- .../share/classes/java/lang/Boolean.java | 4 --- .../share/classes/java/lang/Byte.java | 1 - .../share/classes/java/lang/Class.java | 9 ++++--- .../share/classes/java/lang/Short.java | 1 - .../java/lang/doc-files/ValueBased.html | 22 ++++++++-------- .../classes/java/lang/invoke/MemberName.java | 25 ++++++++++--------- .../java/lang/invoke/MethodHandleProxies.java | 2 +- .../classes/java/lang/reflect/Proxy.java | 5 ++-- .../share/classes/java/util/WeakHashMap.java | 2 +- .../classfile/impl/DirectClassBuilder.java | 1 - .../impl/verifier/VerificationTable.java | 2 +- .../jdk/internal/jimage/ImageReader.java | 1 + src/java.base/share/classes/module-info.java | 9 +++---- .../include/classfile_constants.h.template | 2 +- 15 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src/java.base/share/classes/java/io/ObjectInputStream.java b/src/java.base/share/classes/java/io/ObjectInputStream.java index daed5f3cce5..cd6bd7683f7 100644 --- a/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -2219,7 +2219,7 @@ public class ObjectInputStream * mechanism marks the record as having an exception. * Null is returned from readRecord and later the exception is thrown at * the exit of {@link #readObject(Class)}. - **/ + */ private Object readRecord(ObjectStreamClass desc) throws IOException { ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); if (slots.length != 1) { diff --git a/src/java.base/share/classes/java/lang/Boolean.java b/src/java.base/share/classes/java/lang/Boolean.java index 4c24e98a549..49ab80edfea 100644 --- a/src/java.base/share/classes/java/lang/Boolean.java +++ b/src/java.base/share/classes/java/lang/Boolean.java @@ -28,14 +28,10 @@ package java.lang; import jdk.internal.vm.annotation.IntrinsicCandidate; import java.lang.constant.Constable; -import java.lang.constant.ConstantDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.DynamicConstantDesc; import java.util.Optional; -import static java.lang.constant.ConstantDescs.BSM_GET_STATIC_FINAL; -import static java.lang.constant.ConstantDescs.CD_Boolean; - /** * The {@code Boolean} class is the {@linkplain * java.lang##wrapperClass wrapper class} for values of the primitive diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index 0f3f7f40d05..c2c03e7a3c2 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -36,7 +36,6 @@ import java.util.Optional; import static java.lang.constant.ConstantDescs.BSM_EXPLICIT_CAST; import static java.lang.constant.ConstantDescs.CD_byte; -import static java.lang.constant.ConstantDescs.CD_int; import static java.lang.constant.ConstantDescs.DEFAULT_NAME; /** diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index eab1993a2b4..8a2f722f3dd 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -224,9 +224,9 @@ public final class Class implements java.io.Serializable, AnnotatedElement, TypeDescriptor.OfField>, Constable { - private static final int ANNOTATION= 0x00002000; - private static final int ENUM = 0x00004000; - private static final int SYNTHETIC = 0x00001000; + private static final int ANNOTATION = 0x00002000; + private static final int ENUM = 0x00004000; + private static final int SYNTHETIC = 0x00001000; private static native void registerNatives(); static { @@ -1390,6 +1390,7 @@ public final class Class implements java.io.Serializable, // INNER_CLASS forbids. INNER_CLASS allows PRIVATE, PROTECTED, // and STATIC, which are not allowed on Location.CLASS. // Use getClassFileAccessFlags to expose SUPER status. + // Arrays need to use PRIVATE/PROTECTED from its component modifiers. var location = (isMemberClass() || isLocalClass() || isAnonymousClass() || isArray()) ? AccessFlag.Location.INNER_CLASS : @@ -3779,7 +3780,7 @@ public final class Class implements java.io.Serializable, * @since 1.8 */ public AnnotatedType[] getAnnotatedInterfaces() { - return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this); + return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this); } private native Class getNestHost0(); diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index 920500a7fa3..14f7a267165 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -35,7 +35,6 @@ import java.lang.constant.DynamicConstantDesc; import java.util.Optional; import static java.lang.constant.ConstantDescs.BSM_EXPLICIT_CAST; -import static java.lang.constant.ConstantDescs.CD_int; import static java.lang.constant.ConstantDescs.CD_short; import static java.lang.constant.ConstantDescs.DEFAULT_NAME; diff --git a/src/java.base/share/classes/java/lang/doc-files/ValueBased.html b/src/java.base/share/classes/java/lang/doc-files/ValueBased.html index 6a935afe04b..3b860ce0534 100644 --- a/src/java.base/share/classes/java/lang/doc-files/ValueBased.html +++ b/src/java.base/share/classes/java/lang/doc-files/ValueBased.html @@ -30,35 +30,35 @@

{@index "Value-based Classes"}

-Some classes, such as java.lang.Integer and -java.time.LocalDate, are value-based. +Some classes, such as {@code java.lang.Integer} and +{@code java.time.LocalDate}, are value-based. A value-based class has the following properties:
  • the class declares only final instance fields (though these may contain references to mutable objects);
  • -
  • the class's implementations of equals, hashCode, - and toString compute their results solely from the values +
  • the class's implementations of {@code equals}, {@code hashCode}, + and {@code toString} compute their results solely from the values of the class's instance fields (and the members of the objects they reference), not from the instance's identity;
  • the class's methods treat instances as freely substitutable - when equal, meaning that interchanging any two instances x and - y that are equal according to equals() produces no + when equal, meaning that interchanging any two instances {@code x} and + {@code y} that are equal according to {@code equals()} produces no visible change in the behavior of the class's methods;
  • the class performs no synchronization using an instance's monitor;
  • -
  • the class does not declare (or has deprecated any) accessible constructors;
  • +
  • the class does not declare (or discourages use of) accessible constructors;
  • the class does not provide any instance creation mechanism that promises a unique identity on each method call—in particular, any factory method's contract must allow for the possibility that if two independently-produced - instances are equal according to equals(), they may also be - equal according to ==;
  • -
  • the class is final, and extends either Object or a hierarchy of + instances are equal according to {@code equals()}, they may also be + equal according to {@code ==};
  • +
  • the class is final, and extends either {@code Object} or a hierarchy of abstract classes that declare no instance fields or instance initializers and whose constructors are empty.

When two instances of a value-based class are equal (according to `equals`), a program should not attempt to distinguish between their identities, whether directly via reference - equality or indirectly via an appeal to synchronization, identity hashing, + equality {@code ==} or indirectly via an appeal to synchronization, identity hashing, serialization, or any other identity-sensitive mechanism.

Synchronization on instances of value-based classes is strongly discouraged, diff --git a/src/java.base/share/classes/java/lang/invoke/MemberName.java b/src/java.base/share/classes/java/lang/invoke/MemberName.java index 918d1b10791..d320ad11ade 100644 --- a/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -408,11 +408,12 @@ final class MemberName implements Member, Cloneable { // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo // unofficial modifier flags, used by HotSpot: - static final int BRIDGE = 0x00000040; - static final int VARARGS = 0x00000080; - static final int SYNTHETIC = 0x00001000; - static final int ANNOTATION= 0x00002000; - static final int ENUM = 0x00004000; + static final int BRIDGE = 0x00000040; + static final int VARARGS = 0x00000080; + static final int SYNTHETIC = 0x00001000; + static final int ANNOTATION = 0x00002000; + static final int ENUM = 0x00004000; + /** Utility method to query the modifier flags of this member; returns false if the member is not a method. */ public boolean isBridge() { return allFlagsSet(IS_METHOD | BRIDGE); @@ -426,19 +427,19 @@ final class MemberName implements Member, Cloneable { return allFlagsSet(SYNTHETIC); } - static final String CONSTRUCTOR_NAME = ""; // the ever-popular + static final String CONSTRUCTOR_NAME = ""; // modifiers exported by the JVM: static final int RECOGNIZED_MODIFIERS = 0xFFFF; // private flags, not part of RECOGNIZED_MODIFIERS: static final int - IS_METHOD = MN_IS_METHOD, // method (not constructor) - IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor - IS_FIELD = MN_IS_FIELD, // field - IS_TYPE = MN_IS_TYPE, // nested type - CALLER_SENSITIVE = MN_CALLER_SENSITIVE, // @CallerSensitive annotation detected - TRUSTED_FINAL = MN_TRUSTED_FINAL; // trusted final field + IS_METHOD = MN_IS_METHOD, // method (not constructor) + IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor + IS_FIELD = MN_IS_FIELD, // field + IS_TYPE = MN_IS_TYPE, // nested type + CALLER_SENSITIVE = MN_CALLER_SENSITIVE, // @CallerSensitive annotation detected + TRUSTED_FINAL = MN_TRUSTED_FINAL; // trusted final field static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE; diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java index 16f5c7e59b8..8dac21c8968 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -344,7 +344,7 @@ public final class MethodHandleProxies { ClassLoaders.platformClassLoader() : loader))) .build(proxyDesc, clb -> { clb.withSuperclass(CD_Object) - .withFlags(ACC_FINAL | ACC_SYNTHETIC) + .withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC) .withInterfaceSymbols(ifaceDesc) // static and instance fields .withField(TYPE_NAME, CD_Class, ACC_PRIVATE | ACC_STATIC | ACC_FINAL) diff --git a/src/java.base/share/classes/java/lang/reflect/Proxy.java b/src/java.base/share/classes/java/lang/reflect/Proxy.java index b811deb863d..6ce8e80cdca 100644 --- a/src/java.base/share/classes/java/lang/reflect/Proxy.java +++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package java.lang.reflect; +import java.lang.classfile.ClassFile; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -467,7 +468,7 @@ public class Proxy implements java.io.Serializable { * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, - context.accessFlags() | Modifier.FINAL); + context.accessFlags() | Modifier.FINAL | ClassFile.ACC_SUPER); try { Class pc = JLA.defineClass(loader, proxyName, proxyClassFile, null, "__dynamic_proxy__"); diff --git a/src/java.base/share/classes/java/util/WeakHashMap.java b/src/java.base/share/classes/java/util/WeakHashMap.java index b5a27593840..1412d8f6ff9 100644 --- a/src/java.base/share/classes/java/util/WeakHashMap.java +++ b/src/java.base/share/classes/java/util/WeakHashMap.java @@ -25,8 +25,8 @@ package java.util; -import java.lang.ref.WeakReference; import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 0e82c545359..79c623bc31d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -168,7 +168,6 @@ public final class DirectClassBuilder this.sizeHint = sizeHint; } - public byte[] build() { // The logic of this is very carefully ordered. We want to avoid diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java index 04276b8eeb8..eb3f5ee913d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationTable.java @@ -321,7 +321,7 @@ class VerificationTable { return frame; } int offset_delta = _stream.get_u2(); - if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) { + if (frame_type <= RESERVED_END) { _verifier.classError("reserved frame type"); } if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { diff --git a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java index c36e265ee2f..4c358820166 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java +++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java @@ -821,6 +821,7 @@ public final class ImageReader implements AutoCloseable { this.children = Collections.unmodifiableList(children); } } + /** * Resource node (e.g. a ".class" entry, or any other data resource). * diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index d20f6311bca..665b3a3b98d 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -135,7 +135,6 @@ module java.base { exports javax.security.auth.x500; exports javax.security.cert; - // additional qualified exports may be inserted at build time // see make/gensrc/GenModuleInfo.gmk @@ -147,11 +146,11 @@ module java.base { java.security.sasl; exports jdk.internal to jdk.incubator.vector; - // Note: all modules in the exported list participate in preview features - // and therefore if they use preview features they do not need to be - // compiled with "--enable-preview". + // Note: all modules in the exported list participate in preview features, + // normal or reflective. They do not need to be compiled with "--enable-preview" + // to use preview features and do not need to suppress "preview" warnings. // It is recommended for any modules that do participate that their - // module declaration be annotated with jdk.internal.javac.ParticipatesInPreview + // module declaration be annotated with jdk.internal.javac.ParticipatesInPreview. exports jdk.internal.javac to java.compiler, jdk.compiler; diff --git a/src/java.base/share/native/include/classfile_constants.h.template b/src/java.base/share/native/include/classfile_constants.h.template index fb022ec1fd4..4f96a0673ef 100644 --- a/src/java.base/share/native/include/classfile_constants.h.template +++ b/src/java.base/share/native/include/classfile_constants.h.template @@ -111,7 +111,7 @@ enum { JVM_CONSTANT_InvokeDynamic = 18, JVM_CONSTANT_Module = 19, JVM_CONSTANT_Package = 20, - JVM_CONSTANT_ExternalMax = 20 + JVM_CONSTANT_ExternalMax = 20 }; /* JVM_CONSTANT_MethodHandle subtypes */ From 08c8520b39083ec6354dc5df2f18c1f4c3588053 Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Wed, 4 Mar 2026 20:04:30 +0000 Subject: [PATCH 043/655] 8378698: Optimize Base64.Encoder#encodeToString Reviewed-by: liach, rriggs --- .../share/classes/java/util/Base64.java | 6 +- .../bench/java/util/Base64EncodeToString.java | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/util/Base64EncodeToString.java diff --git a/src/java.base/share/classes/java/util/Base64.java b/src/java.base/share/classes/java/util/Base64.java index ed1a4a8d638..fd714050149 100644 --- a/src/java.base/share/classes/java/util/Base64.java +++ b/src/java.base/share/classes/java/util/Base64.java @@ -32,6 +32,8 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import sun.nio.cs.ISO_8859_1; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -201,6 +203,7 @@ public final class Base64 { * @since 1.8 */ public static class Encoder { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private final byte[] newline; private final int linemax; @@ -344,10 +347,9 @@ public final class Base64 { * the byte array to encode * @return A String containing the resulting Base64 encoded characters */ - @SuppressWarnings("deprecation") public String encodeToString(byte[] src) { byte[] encoded = encode(src); - return new String(encoded, 0, 0, encoded.length); + return JLA.uncheckedNewStringWithLatin1Bytes(encoded); } /** diff --git a/test/micro/org/openjdk/bench/java/util/Base64EncodeToString.java b/test/micro/org/openjdk/bench/java/util/Base64EncodeToString.java new file mode 100644 index 00000000000..5b259230341 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/Base64EncodeToString.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.micro.bench.java.util; + +import org.openjdk.jmh.annotations.*; + +import java.util.Base64; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@State(Scope.Benchmark) +@Warmup(iterations = 5, time = 2) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +public class Base64EncodeToString { + + private byte[] input; + + @Param({"10", "100", "1000", "10000"}) + private int inputSize; + + @Setup + public void setup() { + Random r = new Random(1123); + input = new byte[inputSize]; + r.nextBytes(input); + } + + @Benchmark + public String testEncodeToString() { + return Base64.getEncoder().encodeToString(input); + } +} + From 1f4a7bbb9d67fdaaf63a70d92df895aea41ad201 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 4 Mar 2026 22:42:19 +0000 Subject: [PATCH 044/655] 8379040: Remove inclusion of allocation.hpp from atomicAccess.hpp Reviewed-by: iwalulya, dholmes --- src/hotspot/share/opto/phasetype.hpp | 3 ++- src/hotspot/share/runtime/atomicAccess.hpp | 6 +++--- src/hotspot/share/utilities/bitMap.hpp | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index f388dc6cdc6..ce432fbfc01 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef SHARE_OPTO_PHASETYPE_HPP #define SHARE_OPTO_PHASETYPE_HPP +#include "memory/allocation.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/stringUtils.hpp" diff --git a/src/hotspot/share/runtime/atomicAccess.hpp b/src/hotspot/share/runtime/atomicAccess.hpp index c9a2dfb9383..46330cffdb2 100644 --- a/src/hotspot/share/runtime/atomicAccess.hpp +++ b/src/hotspot/share/runtime/atomicAccess.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #define SHARE_RUNTIME_ATOMICACCESS_HPP #include "cppstdlib/type_traits.hpp" -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" #include "metaprogramming/enableIf.hpp" #include "metaprogramming/primitiveConversions.hpp" #include "runtime/orderAccess.hpp" @@ -829,7 +829,7 @@ class AtomicAccess::PlatformBitops {}; template -class ScopedFenceGeneral: public StackObj { +class ScopedFenceGeneral { public: void prefix() {} void postfix() {} diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp index 5ee462bbe47..17bf437ecae 100644 --- a/src/hotspot/share/utilities/bitMap.hpp +++ b/src/hotspot/share/utilities/bitMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include "utilities/globalDefinitions.hpp" // Forward decl; +class Arena; class BitMapClosure; // Operations for bitmaps represented as arrays of unsigned integers. From c9da76bf33a5e44eb238e3b29eda523e7754b7b6 Mon Sep 17 00:00:00 2001 From: Xiaohong Gong Date: Thu, 5 Mar 2026 01:57:03 +0000 Subject: [PATCH 045/655] 8377449: Strengthen vector IR validation in TestVectorAlgorithms.java for AArch64 Reviewed-by: mhaessig, epeter --- .../vectorization/TestVectorAlgorithms.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java index e02563c2fc2..785a6de30a0 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java @@ -272,8 +272,10 @@ public class TestVectorAlgorithms { @Test @IR(counts = {IRNode.ADD_VI, "> 0", IRNode.STORE_VECTOR, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}) - // Note: also works with NEON/asimd, but only with TieredCompilation. + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, + applyIf = {"TieredCompilation", "true"}) + // IR check only works with TieredCompilation. Needs to make it + // work with -XX:-TieredCompilation in future (see JDK-8378640). public Object iotaI_VectorAPI(int[] r) { return VectorAlgorithmsImpl.iotaI_VectorAPI(r); } @@ -360,7 +362,7 @@ public class TestVectorAlgorithms { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.ADD_REDUCTION_V, "> 0", IRNode.MUL_VF, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, applyIf = {"UseSuperWord", "true"}) public float dotProductF_VectorAPI_naive(float[] a, float[] b) { return VectorAlgorithmsImpl.dotProductF_VectorAPI_naive(a, b); @@ -370,7 +372,7 @@ public class TestVectorAlgorithms { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.ADD_REDUCTION_V, "> 0", IRNode.MUL_VF, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}, applyIf = {"UseSuperWord", "true"}) public float dotProductF_VectorAPI_reduction_after_loop(float[] a, float[] b) { return VectorAlgorithmsImpl.dotProductF_VectorAPI_reduction_after_loop(a, b); @@ -392,7 +394,8 @@ public class TestVectorAlgorithms { IRNode.MUL_VI, IRNode.VECTOR_SIZE_8, "> 0", IRNode.ADD_VI, IRNode.VECTOR_SIZE_8, "> 0", IRNode.ADD_REDUCTION_VI, "> 0"}, - applyIfCPUFeature = {"avx2", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}, + applyIf = {"MaxVectorSize", ">=32"}) public int hashCodeB_VectorAPI_v1(byte[] a) { return VectorAlgorithmsImpl.hashCodeB_VectorAPI_v1(a); } @@ -402,7 +405,7 @@ public class TestVectorAlgorithms { IRNode.MUL_VI, "> 0", IRNode.ADD_VI, "> 0", IRNode.ADD_REDUCTION_VI, "> 0"}, - applyIfCPUFeature = {"avx2", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) public int hashCodeB_VectorAPI_v2(byte[] a) { return VectorAlgorithmsImpl.hashCodeB_VectorAPI_v2(a); } @@ -506,7 +509,7 @@ public class TestVectorAlgorithms { IRNode.VECTOR_TEST, "> 0", IRNode.COMPRESS_VI, "> 0", IRNode.STORE_VECTOR_MASKED, "> 0"}, - applyIfCPUFeature = {"avx2", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) public Object filterI_VectorAPI(int[] a, int[] r, int threshold) { return VectorAlgorithmsImpl.filterI_VectorAPI(a, r, threshold); } @@ -526,7 +529,10 @@ public class TestVectorAlgorithms { IRNode.OR_V_MASK, "> 0", IRNode.ADD_VI, "> 0", IRNode.ADD_REDUCTION_VI, "> 0"}, - applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}, + applyIf = {"TieredCompilation", "true"}) + // IR check only works with TieredCompilation. Needs to make it + // work with -XX:-TieredCompilation in future (see JDK-8378640). public int reduceAddIFieldsX4_VectorAPI(int[] oops, int[] mem) { return VectorAlgorithmsImpl.reduceAddIFieldsX4_VectorAPI(oops, mem); } From c87ecaddfb32485b2ecaecc9284ce37b610ffffc Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Thu, 5 Mar 2026 09:23:21 +0000 Subject: [PATCH 046/655] 8379192: Use an initializer list in the ObjectWaiter constructor Reviewed-by: coleenp, dholmes, aartemov --- src/hotspot/share/runtime/objectMonitor.cpp | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 8c6994c2152..91771772e2c 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -2541,19 +2541,19 @@ bool ObjectMonitor::try_spin(JavaThread* current) { // ----------------------------------------------------------------------------- // wait_set management ... -ObjectWaiter::ObjectWaiter(JavaThread* current) { - _next = nullptr; - _prev = nullptr; - _thread = current; - _monitor = nullptr; - _notifier_tid = 0; - _recursions = 0; - TState = TS_RUN; - _is_wait = false; - _at_reenter = false; - _interrupted = false; - _do_timed_park = false; - _active = false; +ObjectWaiter::ObjectWaiter(JavaThread* current) + : _next(nullptr), + _prev(nullptr), + _thread(current), + _monitor(nullptr), + _notifier_tid(0), + _recursions(0), + TState(TS_RUN), + _is_wait(false), + _at_reenter(false), + _interrupted(false), + _do_timed_park(false), + _active(false) { } const char* ObjectWaiter::getTStateName(ObjectWaiter::TStates state) { From 28e8700f461cee6c80da15c71090eaf608b6f8fa Mon Sep 17 00:00:00 2001 From: David Briemann Date: Thu, 5 Mar 2026 10:08:57 +0000 Subject: [PATCH 047/655] 8378675: PPC64: increase instruction cache line size Reviewed-by: mdoerr --- src/hotspot/cpu/ppc/icache_ppc.cpp | 8 +++- src/hotspot/cpu/ppc/icache_ppc.hpp | 9 ++-- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 39 +++++----------- src/hotspot/cpu/ppc/vm_version_ppc.hpp | 7 ++- .../os_cpu/aix_ppc/vm_version_aix_ppc.cpp | 36 +++++++++++++++ .../os_cpu/linux_ppc/vm_version_linux_ppc.cpp | 44 +++++++++++++++++++ 6 files changed, 105 insertions(+), 38 deletions(-) create mode 100644 src/hotspot/os_cpu/aix_ppc/vm_version_aix_ppc.cpp create mode 100644 src/hotspot/os_cpu/linux_ppc/vm_version_linux_ppc.cpp diff --git a/src/hotspot/cpu/ppc/icache_ppc.cpp b/src/hotspot/cpu/ppc/icache_ppc.cpp index 05ad3c7a30d..f3d51bad18c 100644 --- a/src/hotspot/cpu/ppc/icache_ppc.cpp +++ b/src/hotspot/cpu/ppc/icache_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ */ #include "runtime/icache.hpp" +#include "runtime/vm_version.hpp" // Use inline assembler to implement icache flush. int ICache::ppc64_flush_icache(address start, int lines, int magic) { @@ -67,6 +68,9 @@ int ICache::ppc64_flush_icache(address start, int lines, int magic) { void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) { + guarantee(VM_Version::get_icache_line_size() >= ICache::line_size, + "processors with smaller cache line size are no longer supported"); + *flush_icache_stub = (ICache::flush_icache_stub_t)ICache::ppc64_flush_icache; // First call to flush itself. diff --git a/src/hotspot/cpu/ppc/icache_ppc.hpp b/src/hotspot/cpu/ppc/icache_ppc.hpp index d348cad1c72..024f706182a 100644 --- a/src/hotspot/cpu/ppc/icache_ppc.hpp +++ b/src/hotspot/cpu/ppc/icache_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 SAP SE. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,9 +35,8 @@ class ICache : public AbstractICache { public: enum { - // Actually, cache line size is 64, but keeping it as it is to be - // on the safe side on ALL PPC64 implementations. - log2_line_size = 5, + // Cache line size is 128 on all supported PPC64 implementations. + log2_line_size = 7, line_size = 1 << log2_line_size }; diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 75feb389298..e471f5a6e4f 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -475,19 +475,12 @@ void VM_Version::print_features() { void VM_Version::determine_features() { #if defined(ABI_ELFv2) - // 1 InstWord per call for the blr instruction. - const int code_size = (num_features+1+2*1)*BytesPerInstWord; + const int code_size = (num_features + 1 /*blr*/) * BytesPerInstWord; #else - // 7 InstWords for each call (function descriptor + blr instruction). - const int code_size = (num_features+1+2*7)*BytesPerInstWord; + const int code_size = (num_features + 1 /*blr*/ + 6 /* fd */) * BytesPerInstWord; #endif int features = 0; - // create test area - enum { BUFFER_SIZE = 2*4*K }; // Needs to be >=2* max cache line size (cache line size can't exceed min page size). - char test_area[BUFFER_SIZE]; - char *mid_of_test_area = &test_area[BUFFER_SIZE>>1]; - // Allocate space for the code. ResourceMark rm; CodeBuffer cb("detect_cpu_features", code_size, 0); @@ -497,20 +490,13 @@ void VM_Version::determine_features() { _features = VM_Version::all_features_m; // Emit code. - void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry(); + void (*test)() = (void(*)())(void *)a->function_entry(); uint32_t *code = (uint32_t *)a->pc(); - // Keep R3_ARG1 unmodified, it contains &field (see below). - // Keep R4_ARG2 unmodified, it contains offset = 0 (see below). a->mfdscr(R0); a->darn(R7); a->brw(R5, R6); a->blr(); - // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. - void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->function_entry(); - a->dcbz(R3_ARG1); // R3_ARG1 = addr - a->blr(); - uint32_t *code_end = (uint32_t *)a->pc(); a->flush(); _features = VM_Version::unknown_m; @@ -522,18 +508,9 @@ void VM_Version::determine_features() { Disassembler::decode((u_char*)code, (u_char*)code_end, tty); } - // Measure cache line size. - memset(test_area, 0xFF, BUFFER_SIZE); // Fill test area with 0xFF. - (*zero_cacheline_func_ptr)(mid_of_test_area); // Call function which executes dcbz to the middle. - int count = 0; // count zeroed bytes - for (int i = 0; i < BUFFER_SIZE; i++) if (test_area[i] == 0) count++; - guarantee(is_power_of_2(count), "cache line size needs to be a power of 2"); - _L1_data_cache_line_size = count; - // Execute code. Illegal instructions will be replaced by 0 in the signal handler. VM_Version::_is_determine_features_test_running = true; - // We must align the first argument to 16 bytes because of the lqarx check. - (*test)(align_up((address)mid_of_test_area, 16), 0); + (*test)(); VM_Version::_is_determine_features_test_running = false; // determine which instructions are legal. @@ -550,6 +527,10 @@ void VM_Version::determine_features() { } _features = features; + + _L1_data_cache_line_size = VM_Version::get_dcache_line_size(); + assert(_L1_data_cache_line_size >= DEFAULT_CACHE_LINE_SIZE, + "processors with smaller cache line size are no longer supported"); } // Power 8: Configure Data Stream Control Register. diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.hpp b/src/hotspot/cpu/ppc/vm_version_ppc.hpp index 11dce83bed0..0f4eb3593a3 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2025 SAP SE. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,9 @@ public: static uint64_t _dscr_val; static void initialize_cpu_information(void); + + static int get_dcache_line_size(); + static int get_icache_line_size(); }; #endif // CPU_PPC_VM_VERSION_PPC_HPP diff --git a/src/hotspot/os_cpu/aix_ppc/vm_version_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/vm_version_aix_ppc.cpp new file mode 100644 index 00000000000..8cc8b715201 --- /dev/null +++ b/src/hotspot/os_cpu/aix_ppc/vm_version_aix_ppc.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "runtime/vm_version.hpp" + +#include + +int VM_Version::get_dcache_line_size() { + return _system_configuration.dcache_line; +} + +int VM_Version::get_icache_line_size() { + return _system_configuration.icache_line; +} diff --git a/src/hotspot/os_cpu/linux_ppc/vm_version_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/vm_version_linux_ppc.cpp new file mode 100644 index 00000000000..d64340edf5c --- /dev/null +++ b/src/hotspot/os_cpu/linux_ppc/vm_version_linux_ppc.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "runtime/vm_version.hpp" + +#include + +int VM_Version::get_dcache_line_size() { + // This should work on all modern linux versions: + int size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + // It may fail with very old linux / glibc versions. We use DEFAULT_CACHE_LINE_SIZE in this case. + // That is the correct value for all currently supported processors. + return (size <= 0) ? DEFAULT_CACHE_LINE_SIZE : size; +} + +int VM_Version::get_icache_line_size() { + // This should work on all modern linux versions: + int size = sysconf(_SC_LEVEL1_ICACHE_LINESIZE); + // It may fail with very old linux / glibc versions. We use DEFAULT_CACHE_LINE_SIZE in this case. + // That is the correct value for all currently supported processors. + return (size <= 0) ? DEFAULT_CACHE_LINE_SIZE : size; +} From c9a0e365083a7868c49f082623d722e721838642 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Thu, 5 Mar 2026 10:13:26 +0000 Subject: [PATCH 048/655] 8378376: DaCapo-h2-large regression after JDK-8238686 Reviewed-by: kbarrett, tschatzl --- src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp | 8 +++++++- src/hotspot/share/gc/shared/collectedHeap.hpp | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp index 4dd0a509bcd..1b9704e8ad3 100644 --- a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -366,6 +366,12 @@ static size_t target_heap_capacity(size_t used_bytes, uintx free_ratio) { } size_t G1HeapSizingPolicy::full_collection_resize_amount(bool& expand, size_t allocation_word_size) { + // User-requested Full GCs introduce GC load unrelated to heap size; reset CPU + // usage tracking so heap resizing heuristics are driven only by GC pressure. + if (GCCause::is_user_requested_gc(_g1h->gc_cause())) { + reset_cpu_usage_tracking_data(); + } + const size_t capacity_after_gc = _g1h->capacity(); // Capacity, free and used after the GC counted as full regions to // include the waste in the following calculations. diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index f13c3ab7b6e..100866bb528 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -289,7 +289,7 @@ protected: DEBUG_ONLY(bool is_in_or_null(const void* p) const { return p == nullptr || is_in(p); }) void set_gc_cause(GCCause::Cause v); - GCCause::Cause gc_cause() { return _gc_cause; } + GCCause::Cause gc_cause() const { return _gc_cause; } oop obj_allocate(Klass* klass, size_t size, TRAPS); virtual oop array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS); From ec3b58b5e0c93c9e32a59dd1b65bd3b9dea6e12b Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 5 Mar 2026 10:37:23 +0000 Subject: [PATCH 049/655] 8379162: AggregateRequestBodyTest.java intermittent fails "Connection closed by client peer: APPLICATION_ERROR" Reviewed-by: jpai, syan, djelinski --- .../httpclient/AggregateRequestBodyTest.java | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java b/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java index 175e860c229..fb67cf02566 100644 --- a/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java +++ b/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java @@ -74,6 +74,7 @@ import static java.lang.System.out; import static java.net.http.HttpClient.Version.HTTP_1_1; import static java.net.http.HttpClient.Version.HTTP_2; import static java.net.http.HttpClient.Version.HTTP_3; +import static java.net.http.HttpOption.H3_DISCOVERY; import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; import org.junit.jupiter.api.AfterAll; @@ -81,7 +82,6 @@ import org.junit.jupiter.api.Assertions; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; @@ -219,7 +219,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { int i = 0; for (boolean sameClient : List.of(false, true)) { for (URI uri : uris()) { - HttpClient.Version version = null; + final HttpClient.Version version; if (uri.equals(http1URI) || uri.equals(https1URI)) version = HttpClient.Version.HTTP_1_1; else if (uri.equals(http2URI) || uri.equals(https2URI)) version = HttpClient.Version.HTTP_2; else if (uri.equals(http3URI)) version = HTTP_3; @@ -295,7 +295,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { static List lengths(long... lengths) { return LongStream.of(lengths) - .mapToObj(Long::valueOf) + .boxed() .collect(Collectors.toList()); } @@ -446,7 +446,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { @Override public void onComplete() { - resultCF.complete(items.stream().collect(Collectors.toUnmodifiableList())); + resultCF.complete(items.stream().toList()); } public ByteBuffer take() { @@ -552,7 +552,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { subscriber.subscriptionCF.thenAccept(s -> s.request(Long.MAX_VALUE)); if (errorPublisher.hasErrors()) { CompletionException ce = Assertions.assertThrows(CompletionException.class, - () -> subscriber.resultCF.join()); + subscriber.resultCF::join); out.println(description + ": got expected " + ce); assertEquals(Exception.class, ce.getCause().getClass()); assertEquals(result, stringFromBytes(subscriber.items.stream()) + ""); @@ -600,7 +600,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { description.replace("null", "length(-1)")); } - private static final Throwable completionCause(CompletionException x) { + private static Throwable completionCause(CompletionException x) { while (x.getCause() instanceof CompletionException) { x = (CompletionException)x.getCause(); } @@ -618,7 +618,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { publisher.subscribe(subscriber); Subscription subscription = subscriber.subscriptionCF.join(); subscription.request(n); - CompletionException expected = Assertions.assertThrows(CE, () -> subscriber.resultCF.join()); + CompletionException expected = Assertions.assertThrows(CE, subscriber.resultCF::join); Throwable cause = completionCause(expected); if (cause instanceof IllegalArgumentException) { System.out.printf("Got expected IAE for %d: %s%n", n, cause); @@ -655,7 +655,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { assertTrue(requestSubscriber1.resultCF().isDone()); String result1 = stringFromBytes(list1.stream()); assertEquals("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", result1); - System.out.println("Got expected sentence with one request: \"%s\"".formatted(result1)); + System.out.printf("Got expected sentence with one request: \"%s\"%n", result1); // Test that we can split our requests call any which way we want // (whether in the 'middle of a publisher' or at the boundaries. @@ -824,7 +824,7 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { .toArray(HttpRequest.BodyPublisher[]::new) ); - HttpRequest request = HttpRequest.newBuilder(uri) + HttpRequest request = newRequestBuilder(uri) .version(version) .POST(publisher) .build(); @@ -835,13 +835,21 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { HttpResponse response = client.send(request, BodyHandlers.ofString()); int expectedResponse = RESPONSE_CODE; if (response.statusCode() != expectedResponse) - throw new RuntimeException("wrong response code " + Integer.toString(response.statusCode())); + throw new RuntimeException("wrong response code " + response.statusCode()); assertEquals(BODIES.stream().collect(Collectors.joining()), response.body()); } if (!sameClient) client.close(); System.out.println("test: DONE"); } + private static HttpRequest.Builder newRequestBuilder(URI uri) { + var builder = HttpRequest.newBuilder(uri); + if (uri.getPath().contains("/http3/")) { + builder.setOption(H3_DISCOVERY, HTTP_3_URI_ONLY); + } + return builder; + } + private static URI buildURI(String scheme, String path, int port) { return URIBuilder.newBuilder() .scheme(scheme) @@ -882,11 +890,17 @@ public class AggregateRequestBodyTest implements HttpServerAdapters { http3TestServer.start(); } + private static void close(AutoCloseable closeable) throws Exception { + if (closeable == null) return; + out.println("Closing shared client " + closeable); + closeable.close(); + } + @AfterAll public static void teardown() throws Exception { String sharedClientName = sharedClient == null ? null : sharedClient.toString(); - sharedClient.close(); + close(sharedClient); sharedClient = null; Thread.sleep(100); AssertionError fail = TRACKER.check(500); From 8a9b63f76fd678c6883a51332aeb84846791ed5e Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Thu, 5 Mar 2026 11:05:01 +0000 Subject: [PATCH 050/655] 8378413: C2: Missed Ideal optimization opportunity in PhaseIterGVN for URShiftI still exists Reviewed-by: qamai, dlong --- src/hotspot/share/opto/mulnode.cpp | 18 ++- .../c2/gvn/MissedURShiftIAddILShiftIdeal.java | 134 ++++++++++++++++++ 2 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/gvn/MissedURShiftIAddILShiftIdeal.java diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 9bdaa3b9f34..cac9f1dcc37 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -1539,15 +1539,20 @@ Node* URShiftINode::Ideal(PhaseGVN* phase, bool can_reshape) { Node *add = in(1); if (in1_op == Op_AddI) { Node *lshl = add->in(1); + Node *y = add->in(2); + if (lshl->Opcode() != Op_LShiftI) { + lshl = add->in(2); + y = add->in(1); + } // Compare shift counts by value, not by node pointer, to also match a not-yet-normalized // negative constant (e.g. -1 vs 31) int lshl_con = 0; if (lshl->Opcode() == Op_LShiftI && const_shift_count(phase, lshl, &lshl_con) && (lshl_con & (BitsPerJavaInteger - 1)) == con) { - Node *y_z = phase->transform( new URShiftINode(add->in(2),in(2)) ); - Node *sum = phase->transform( new AddINode( lshl->in(1), y_z ) ); - return new AndINode( sum, phase->intcon(mask) ); + Node *y_z = phase->transform(new URShiftINode(y, in(2))); + Node *sum = phase->transform(new AddINode(lshl->in(1), y_z)); + return new AndINode(sum, phase->intcon(mask)); } } @@ -1699,13 +1704,18 @@ Node* URShiftLNode::Ideal(PhaseGVN* phase, bool can_reshape) { const TypeInt *t2 = phase->type(in(2))->isa_int(); if (add->Opcode() == Op_AddL) { Node *lshl = add->in(1); + Node *y = add->in(2); + if (lshl->Opcode() != Op_LShiftL) { + lshl = add->in(2); + y = add->in(1); + } // Compare shift counts by value, not by node pointer, to also match a not-yet-normalized // negative constant (e.g. -1 vs 63) int lshl_con = 0; if (lshl->Opcode() == Op_LShiftL && const_shift_count(phase, lshl, &lshl_con) && (lshl_con & (BitsPerJavaLong - 1)) == con) { - Node* y_z = phase->transform(new URShiftLNode(add->in(2), in(2))); + Node* y_z = phase->transform(new URShiftLNode(y, in(2))); Node* sum = phase->transform(new AddLNode(lshl->in(1), y_z)); return new AndLNode(sum, phase->longcon(mask)); } diff --git a/test/hotspot/jtreg/compiler/c2/gvn/MissedURShiftIAddILShiftIdeal.java b/test/hotspot/jtreg/compiler/c2/gvn/MissedURShiftIAddILShiftIdeal.java new file mode 100644 index 00000000000..a1f4f011466 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/MissedURShiftIAddILShiftIdeal.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2.gvn; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8378413 + * @key randomness + * @summary Verify that URShift{I,L}Node::Ideal optimizes ((x << C) + y) >>> C + * regardless of Add input order, i.e. it is commutative w.r.t. the addition. + * @library /test/lib / + * @run driver ${test.main.class} + * @run driver ${test.main.class} -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -XX:VerifyIterativeGVN=1110 -Xbatch -XX:CompileCommand=compileonly,${test.main.class}::* + */ +public class MissedURShiftIAddILShiftIdeal { + + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = {"testI", "testICommuted", "testIComputedY", + "testL", "testLCommuted", "testLComputedY"}) + public void runMethod() { + int xi = RANDOM.nextInt(); + int yi = RANDOM.nextInt(); + int ai = RANDOM.nextInt(); + int bi = RANDOM.nextInt(); + long xl = RANDOM.nextLong(); + long yl = RANDOM.nextLong(); + long al = RANDOM.nextLong(); + long bl = RANDOM.nextLong(); + + assertResultI(xi, yi, ai, bi); + assertResultL(xl, yl, al, bl); + } + + @DontCompile + public void assertResultI(int x, int y, int a, int b) { + Asserts.assertEQ(((x << 3) + y) >>> 3, testI(x, y)); + Asserts.assertEQ((y + (x << 5)) >>> 5, testICommuted(x, y)); + Asserts.assertEQ(((x << 7) + (a ^ b)) >>> 7, testIComputedY(x, a, b)); + } + + @DontCompile + public void assertResultL(long x, long y, long a, long b) { + Asserts.assertEQ(((x << 9) + y) >>> 9, testL(x, y)); + Asserts.assertEQ((y + (x << 11)) >>> 11, testLCommuted(x, y)); + Asserts.assertEQ(((x << 13) + (a ^ b)) >>> 13, testLComputedY(x, a, b)); + } + + @Test + // ((x << 3) + y) >>> 3 => (x + (y >>> 3)) & mask + @IR(counts = {IRNode.LSHIFT_I, "0", + IRNode.URSHIFT_I, "1", + IRNode.AND_I, "1"}) + static int testI(int x, int y) { + return ((x << 3) + y) >>> 3; + } + + @Test + // (y + (x << 5)) >>> 5 => (x + (y >>> 5)) & mask (commuted Add) + @IR(counts = {IRNode.LSHIFT_I, "0", + IRNode.URSHIFT_I, "1", + IRNode.AND_I, "1"}) + static int testICommuted(int x, int y) { + return (y + (x << 5)) >>> 5; + } + + @Test + // ((x << 7) + (a ^ b)) >>> 7 => (x + ((a ^ b) >>> 7)) & mask + // Computed y (a ^ b) has higher _idx than LShift, so LShift stays in Add's in(1). + @IR(counts = {IRNode.LSHIFT_I, "0", + IRNode.URSHIFT_I, "1", + IRNode.AND_I, "1"}) + static int testIComputedY(int x, int a, int b) { + return ((x << 7) + (a ^ b)) >>> 7; + } + + @Test + // ((x << 9) + y) >>> 9 => (x + (y >>> 9)) & mask + @IR(counts = {IRNode.LSHIFT_L, "0", + IRNode.URSHIFT_L, "1", + IRNode.AND_L, "1"}) + static long testL(long x, long y) { + return ((x << 9) + y) >>> 9; + } + + @Test + // (y + (x << 11)) >>> 11 => (x + (y >>> 11)) & mask (commuted Add) + @IR(counts = {IRNode.LSHIFT_L, "0", + IRNode.URSHIFT_L, "1", + IRNode.AND_L, "1"}) + static long testLCommuted(long x, long y) { + return (y + (x << 11)) >>> 11; + } + + @Test + // ((x << 13) + (a ^ b)) >>> 13 => (x + ((a ^ b) >>> 13)) & mask + // Computed y (a ^ b) has higher _idx than LShift, so LShift stays in Add's in(1). + @IR(counts = {IRNode.LSHIFT_L, "0", + IRNode.URSHIFT_L, "1", + IRNode.AND_L, "1"}) + static long testLComputedY(long x, long a, long b) { + return ((x << 13) + (a ^ b)) >>> 13; + } +} From 97b78f04230452b675a31d8e37f300a2d31e62ed Mon Sep 17 00:00:00 2001 From: Eric Fang Date: Thu, 5 Mar 2026 11:12:08 +0000 Subject: [PATCH 051/655] 8374349: [VectorAPI]: AArch64: Prefer merging mode SVE CPY instruction Reviewed-by: aph --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 8 +++---- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 21 +++++++++++++++++++ .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 5 +++++ .../cpu/aarch64/vm_version_aarch64.hpp | 5 +++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 19b3bb1a65b..67cf77989d2 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -3814,8 +3814,8 @@ public: } private: - void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, int imm8, - bool isMerge, bool isFloat) { + void _sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, int imm8, + bool isMerge, bool isFloat) { starti; assert(T != Q, "invalid size"); int sh = 0; @@ -3839,11 +3839,11 @@ private: public: // SVE copy signed integer immediate to vector elements (predicated) void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, int imm8, bool isMerge) { - sve_cpy(Zd, T, Pg, imm8, isMerge, /*isFloat*/false); + _sve_cpy(Zd, T, Pg, imm8, isMerge, /*isFloat*/false); } // SVE copy floating-point immediate to vector elements (predicated) void sve_cpy(FloatRegister Zd, SIMD_RegVariant T, PRegister Pg, double d) { - sve_cpy(Zd, T, Pg, checked_cast(pack(d)), /*isMerge*/true, /*isFloat*/true); + _sve_cpy(Zd, T, Pg, checked_cast(pack(d)), /*isMerge*/true, /*isFloat*/true); } // SVE conditionally select elements from two vectors diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index dc0b9eb9546..7aab7d389e1 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -2875,3 +2875,24 @@ void C2_MacroAssembler::vector_expand_sve(FloatRegister dst, FloatRegister src, // dst = 00 87 00 65 00 43 00 21 sve_tbl(dst, size, src, dst); } + +// Optimized SVE cpy (imm, zeroing) instruction. +// +// `movi; cpy(imm, merging)` and `cpy(imm, zeroing)` have the same +// functionality, but test results show that `movi; cpy(imm, merging)` has +// higher throughput on some microarchitectures. This would depend on +// microarchitecture and so may vary between implementations. +void C2_MacroAssembler::sve_cpy(FloatRegister dst, SIMD_RegVariant T, + PRegister pg, int imm8, bool isMerge) { + if (VM_Version::prefer_sve_merging_mode_cpy() && !isMerge) { + // Generates a NEON instruction `movi V.2d, #0`. + // On AArch64, Z and V registers alias in the low 128 bits, so V is + // the low 128 bits of Z. A write to V also clears all bits of + // Z above 128, so this `movi` instruction effectively zeroes the + // entire Z register. According to the Arm Software Optimization + // Guide, `movi` is zero latency. + movi(dst, T2D, 0); + isMerge = true; + } + Assembler::sve_cpy(dst, T, pg, imm8, isMerge); +} diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 4f3a41da402..5c05832afbe 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -75,6 +75,8 @@ unsigned vector_length_in_bytes); public: + using Assembler::sve_cpy; + // jdk.internal.util.ArraysSupport.vectorizedHashCode address arrays_hashcode(Register ary, Register cnt, Register result, FloatRegister vdata0, FloatRegister vdata1, FloatRegister vdata2, FloatRegister vdata3, @@ -244,4 +246,7 @@ void vector_expand_sve(FloatRegister dst, FloatRegister src, PRegister pg, FloatRegister tmp1, FloatRegister tmp2, BasicType bt, int vector_length_in_bytes); + + void sve_cpy(FloatRegister dst, SIMD_RegVariant T, PRegister pg, int imm8, + bool isMerge); #endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 0213872852b..e8681611234 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -55,6 +55,9 @@ protected: static int _max_supported_sve_vector_length; static bool _rop_protection; static uintptr_t _pac_mask; + // When _prefer_sve_merging_mode_cpy is true, `cpy (imm, zeroing)` is + // implemented as `movi; cpy(imm, merging)`. + static constexpr bool _prefer_sve_merging_mode_cpy = true; static SpinWait _spin_wait; @@ -242,6 +245,8 @@ public: static bool use_rop_protection() { return _rop_protection; } + static bool prefer_sve_merging_mode_cpy() { return _prefer_sve_merging_mode_cpy; } + // For common 64/128-bit unpredicated vector operations, we may prefer // emitting NEON instructions rather than the corresponding SVE instructions. static bool use_neon_for_vector(int vector_length_in_bytes) { From fc77e3e9a2bedd3cefc98ca28516eb85ceefe2e5 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 5 Mar 2026 11:12:33 +0000 Subject: [PATCH 052/655] 8378599: Refactor tests under test/jdk/java/net/httpclient/whitebox from TestNG to JUnit Reviewed-by: vyazici, syan --- .../httpclient/whitebox/AltSvcFrameTest.java | 36 +++--- .../whitebox/AltSvcRegistryTest.java | 21 +-- .../AuthenticationFilterTestDriver.java | 4 +- .../whitebox/DefaultProxyDriver.java | 4 +- .../httpclient/whitebox/DemandTestDriver.java | 4 +- .../httpclient/whitebox/FlowTestDriver.java | 4 +- .../whitebox/FramesDecoderTestDriver.java | 4 +- .../whitebox/Http1HeaderParserTestDriver.java | 4 +- .../whitebox/MinimalFutureTestDriver.java | 4 +- .../whitebox/RawChannelTestDriver.java | 6 +- .../whitebox/SSLEchoTubeTestDriver.java | 4 +- .../whitebox/SSLFlowDelegateTestDriver.java | 4 +- .../whitebox/SSLTubeTestDriver.java | 4 +- .../whitebox/SelectorTestDriver.java | 4 +- .../whitebox/WindowControllerTestDriver.java | 4 +- .../whitebox/WrapperTestDriver.java | 4 +- .../net/http/AbstractSSLTubeTest.java | 6 +- .../net/http/AuthenticationFilterTest.java | 61 ++++----- .../jdk/internal/net/http/DefaultProxy.java | 33 ++--- .../jdk/internal/net/http/FlowTest.java | 16 +-- .../net/http/Http1HeaderParserTest.java | 47 +++---- .../jdk/internal/net/http/RawChannelTest.java | 11 +- .../internal/net/http/SSLEchoTubeTest.java | 6 +- .../net/http/SSLFlowDelegateTest.java | 75 +++++------ .../jdk/internal/net/http/SSLTubeTest.java | 14 +- .../jdk/internal/net/http/SelectorTest.java | 6 +- .../net/http/WindowControllerTest.java | 121 +++++++++--------- .../jdk/internal/net/http/WrapperTest.java | 7 +- .../internal/net/http/common/DemandTest.java | 63 +++++---- .../net/http/common/MinimalFutureTest.java | 15 +-- .../net/http/frame/FramesDecoderTest.java | 32 ++--- 31 files changed, 324 insertions(+), 304 deletions(-) diff --git a/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java b/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java index 589e5409044..b9e5f2d58fe 100644 --- a/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java +++ b/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,17 +48,19 @@ import jdk.internal.net.http.HttpClientAccess; import jdk.internal.net.http.common.HttpHeadersBuilder; import jdk.internal.net.http.frame.AltSvcFrame; import jdk.test.lib.net.SimpleSSLContext; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import static java.net.http.HttpResponse.BodyHandlers.ofString; import static jdk.internal.net.http.AltServicesRegistry.AltService; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test - * @summary This test verifies alt-svc registry updation for frames + * @summary This test verifies alt-svc registry updating for frames * @library /test/lib /test/jdk/java/net/httpclient/lib * @build java.net.http/jdk.internal.net.http.HttpClientAccess * jdk.httpclient.test.lib.http2.Http2TestServer @@ -82,7 +84,7 @@ import static org.testng.Assert.assertTrue; * java.base/sun.net.www.http * java.base/sun.net.www * java.base/sun.net - * @run testng/othervm + * @run junit/othervm * -Dtest.requiresHost=true * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.disableHostnameVerification @@ -90,7 +92,6 @@ import static org.testng.Assert.assertTrue; * AltSvcFrameTest */ - public class AltSvcFrameTest { private static final String IGNORED_HOST = "www.should-be-ignored.com"; @@ -109,18 +110,23 @@ public class AltSvcFrameTest { static HttpClient client; private static final SSLContext server = SimpleSSLContext.findSSLContext(); - @BeforeTest - public void setUp() throws Exception { + @BeforeAll + public static void setUp() throws Exception { getRegistry(); https2Server = new Http2TestServer("localhost", true, server); https2Server.addHandler(new AltSvcFrameTestHandler(), "/"); https2Server.setExchangeSupplier(AltSvcFrameTest.CFTHttp2TestExchange::new); https2Server.start(); https2URI = "https://" + https2Server.serverAuthority() + "/"; - - } + @AfterAll + public static void tearDown() { + if (client != null) client.close(); + if (https2Server != null) https2Server.stop(); + } + + static AltServicesRegistry getRegistry() { client = HttpClient.newBuilder() .sslContext(server) @@ -139,7 +145,7 @@ public class AltSvcFrameTest { .GET() .build(); HttpResponse response = client.send(request, ofString()); - assertEquals(response.statusCode(), 200, "unexpected response code"); + assertEquals(200, response.statusCode(), "unexpected response code"); final List services = registry.lookup(URI.create(https2URI), "h3").toList(); System.out.println("Alt services in registry for " + https2URI + " = " + services); final boolean hasExpectedAltSvc = services.stream().anyMatch( @@ -158,7 +164,7 @@ public class AltSvcFrameTest { .GET() .build(); HttpResponse response = client.send(request, ofString()); - assertEquals(response.statusCode(), 200, "unexpected response code"); + assertEquals(200, response.statusCode(), "unexpected response code"); final List services = registry.lookup( URI.create(FOO_BAR_ORIGIN), "h3").toList(); System.out.println("Alt services in registry for " + FOO_BAR_ORIGIN + " = " + services); diff --git a/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java b/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java index b853f715415..682082ba9f8 100644 --- a/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java +++ b/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,6 @@ import jdk.internal.net.http.AltServicesRegistry; import jdk.test.lib.net.SimpleSSLContext; import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import java.io.IOException; @@ -46,6 +44,10 @@ import java.util.concurrent.Executors; import static jdk.internal.net.http.AltServicesRegistry.AltService; import static java.net.http.HttpResponse.BodyHandlers.ofString; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; + /* * @test * @summary This test verifies alt-svc registry updates @@ -73,7 +75,7 @@ import static java.net.http.HttpResponse.BodyHandlers.ofString; * java.base/sun.net.www * java.base/sun.net * java.base/jdk.internal.util - * @run testng/othervm + * @run junit/othervm * -Dtest.requiresHost=true * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.disableHostnameVerification @@ -81,7 +83,6 @@ import static java.net.http.HttpResponse.BodyHandlers.ofString; * AltSvcRegistryTest */ - public class AltSvcRegistryTest implements HttpServerAdapters { static HttpTestServer https2Server; @@ -89,8 +90,8 @@ public class AltSvcRegistryTest implements HttpServerAdapters { static HttpClient client; private static final SSLContext server = SimpleSSLContext.findSSLContext(); - @BeforeTest - public void setUp() throws Exception { + @BeforeAll + public static void setUp() throws Exception { getRegistry(); final ExecutorService executor = Executors.newCachedThreadPool(); https2Server = HttpServerAdapters.HttpTestServer.of( @@ -98,8 +99,12 @@ public class AltSvcRegistryTest implements HttpServerAdapters { https2Server.addHandler(new AltSvcRegistryTestHandler("https", https2Server), "/"); https2Server.start(); https2URI = "https://" + https2Server.serverAuthority() + "/"; + } - + @AfterAll + public static void tearDown() { + if (client != null) client.close(); + if (https2Server != null) https2Server.stop(); } static AltServicesRegistry getRegistry() { diff --git a/test/jdk/java/net/httpclient/whitebox/AuthenticationFilterTestDriver.java b/test/jdk/java/net/httpclient/whitebox/AuthenticationFilterTestDriver.java index e932455e409..5808c380593 100644 --- a/test/jdk/java/net/httpclient/whitebox/AuthenticationFilterTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/AuthenticationFilterTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,5 +24,5 @@ /* * @test * @modules java.net.http/jdk.internal.net.http - * @run testng java.net.http/jdk.internal.net.http.AuthenticationFilterTest + * @run junit java.net.http/jdk.internal.net.http.AuthenticationFilterTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/DefaultProxyDriver.java b/test/jdk/java/net/httpclient/whitebox/DefaultProxyDriver.java index 5c18fd84a0f..54127855386 100644 --- a/test/jdk/java/net/httpclient/whitebox/DefaultProxyDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/DefaultProxyDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @summary Verifies that the HTTP Client, by default, uses the system-wide * proxy selector, and that that selector supports the standard HTTP proxy * system properties. - * @run testng/othervm + * @run junit/othervm * -Dhttp.proxyHost=foo.proxy.com * -Dhttp.proxyPort=9876 * -Dhttp.nonProxyHosts=*.direct.com diff --git a/test/jdk/java/net/httpclient/whitebox/DemandTestDriver.java b/test/jdk/java/net/httpclient/whitebox/DemandTestDriver.java index ea442878261..c8b793a289c 100644 --- a/test/jdk/java/net/httpclient/whitebox/DemandTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/DemandTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,5 +24,5 @@ /* * @test * @modules java.net.http/jdk.internal.net.http.common - * @run testng java.net.http/jdk.internal.net.http.common.DemandTest + * @run junit java.net.http/jdk.internal.net.http.common.DemandTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java b/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java index c24a733db3b..4468b5d6eb6 100644 --- a/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/FlowTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,5 +25,5 @@ * @test * @compile/module=java.net.http ../../../../../../lib/jdk/test/lib/net/SimpleSSLContext.java * @modules java.net.http/jdk.internal.net.http - * @run testng/timeout=480 java.net.http/jdk.internal.net.http.FlowTest + * @run junit/timeout=480 java.net.http/jdk.internal.net.http.FlowTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/FramesDecoderTestDriver.java b/test/jdk/java/net/httpclient/whitebox/FramesDecoderTestDriver.java index 9b3c8878669..7edc555d8a6 100644 --- a/test/jdk/java/net/httpclient/whitebox/FramesDecoderTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/FramesDecoderTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8195823 * @modules java.net.http/jdk.internal.net.http.frame - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * java.net.http/jdk.internal.net.http.frame.FramesDecoderTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/Http1HeaderParserTestDriver.java b/test/jdk/java/net/httpclient/whitebox/Http1HeaderParserTestDriver.java index b18142601a5..f3b9d410b51 100644 --- a/test/jdk/java/net/httpclient/whitebox/Http1HeaderParserTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/Http1HeaderParserTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,5 +25,5 @@ * @test * @bug 8195138 * @modules java.net.http/jdk.internal.net.http - * @run testng java.net.http/jdk.internal.net.http.Http1HeaderParserTest + * @run junit java.net.http/jdk.internal.net.http.Http1HeaderParserTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/MinimalFutureTestDriver.java b/test/jdk/java/net/httpclient/whitebox/MinimalFutureTestDriver.java index 316ca29e2a6..90fe6816adc 100644 --- a/test/jdk/java/net/httpclient/whitebox/MinimalFutureTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/MinimalFutureTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,5 +24,5 @@ /* * @test * @modules java.net.http/jdk.internal.net.http.common - * @run testng java.net.http/jdk.internal.net.http.common.MinimalFutureTest + * @run junit java.net.http/jdk.internal.net.http.common.MinimalFutureTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/RawChannelTestDriver.java b/test/jdk/java/net/httpclient/whitebox/RawChannelTestDriver.java index ab44fba5ecd..7ca448b7892 100644 --- a/test/jdk/java/net/httpclient/whitebox/RawChannelTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/RawChannelTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,10 @@ * @test * @bug 8151299 8164704 * @modules java.net.http/jdk.internal.net.http - * @run testng/othervm java.net.http/jdk.internal.net.http.RawChannelTest + * @run junit/othervm java.net.http/jdk.internal.net.http.RawChannelTest */ // use -// @run testng/othervm -Dseed=6434511950803022575 +// @run junit/othervm -Dseed=6434511950803022575 // java.net.http/jdk.internal.net.http.RawChannelTest // to reproduce a failure with a particular seed (e.g. 6434511950803022575) // if this test is observed failing with that seed diff --git a/test/jdk/java/net/httpclient/whitebox/SSLEchoTubeTestDriver.java b/test/jdk/java/net/httpclient/whitebox/SSLEchoTubeTestDriver.java index d641513b298..b4b3e59326d 100644 --- a/test/jdk/java/net/httpclient/whitebox/SSLEchoTubeTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/SSLEchoTubeTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @compile/module=java.net.http ../../../../../../lib/jdk/test/lib/net/SimpleSSLContext.java * @modules java.net.http/jdk.internal.net.http - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * java.net.http/jdk.internal.net.http.SSLEchoTubeTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/SSLFlowDelegateTestDriver.java b/test/jdk/java/net/httpclient/whitebox/SSLFlowDelegateTestDriver.java index a49f53a844a..cb8e9801ca8 100644 --- a/test/jdk/java/net/httpclient/whitebox/SSLFlowDelegateTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/SSLFlowDelegateTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * downReader doesn't request any * @compile/module=java.net.http ../../../../../../lib/jdk/test/lib/net/SimpleSSLContext.java * @modules java.net.http/jdk.internal.net.http - * @run testng/othervm -Djdk.internal.httpclient.debug=true + * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djavax.net.debug=ssl:handshake * java.net.http/jdk.internal.net.http.SSLFlowDelegateTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/SSLTubeTestDriver.java b/test/jdk/java/net/httpclient/whitebox/SSLTubeTestDriver.java index b1994777b14..2c73de26648 100644 --- a/test/jdk/java/net/httpclient/whitebox/SSLTubeTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/SSLTubeTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @compile/module=java.net.http ../../../../../../lib/jdk/test/lib/net/SimpleSSLContext.java * @modules java.net.http/jdk.internal.net.http - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * java.net.http/jdk.internal.net.http.SSLTubeTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/SelectorTestDriver.java b/test/jdk/java/net/httpclient/whitebox/SelectorTestDriver.java index 226e644e903..54d66d04cff 100644 --- a/test/jdk/java/net/httpclient/whitebox/SelectorTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/SelectorTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,5 +25,5 @@ * @test * @bug 8151299 8164704 * @modules java.net.http/jdk.internal.net.http - * @run testng java.net.http/jdk.internal.net.http.SelectorTest + * @run junit java.net.http/jdk.internal.net.http.SelectorTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/WindowControllerTestDriver.java b/test/jdk/java/net/httpclient/whitebox/WindowControllerTestDriver.java index 7943bfceaa0..16ac4aaefb8 100644 --- a/test/jdk/java/net/httpclient/whitebox/WindowControllerTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/WindowControllerTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,5 +26,5 @@ * @bug 8207960 * @modules java.net.http/jdk.internal.net.http * @summary Non-negative WINDOW_UPDATE increments may leave the stream window size negative - * @run testng/othervm java.net.http/jdk.internal.net.http.WindowControllerTest + * @run junit/othervm java.net.http/jdk.internal.net.http.WindowControllerTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/WrapperTestDriver.java b/test/jdk/java/net/httpclient/whitebox/WrapperTestDriver.java index 7ea2b07e3a7..dfc808ff68b 100644 --- a/test/jdk/java/net/httpclient/whitebox/WrapperTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/WrapperTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,5 +24,5 @@ /* * @test * @modules java.net.http/jdk.internal.net.http - * @run testng java.net.http/jdk.internal.net.http.WrapperTest + * @run junit java.net.http/jdk.internal.net.http.WrapperTest */ diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AbstractSSLTubeTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AbstractSSLTubeTest.java index 944f8ae0872..699b537c980 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AbstractSSLTubeTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AbstractSSLTubeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,17 +26,13 @@ package jdk.internal.net.http; import jdk.internal.net.http.common.FlowTube; import jdk.internal.net.http.common.SSLTube; import jdk.internal.net.http.common.Utils; -import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.nio.ByteBuffer; import java.util.List; -import java.util.StringTokenizer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AuthenticationFilterTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AuthenticationFilterTest.java index 415caeb1196..2e9672e4725 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AuthenticationFilterTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/AuthenticationFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,6 @@ package jdk.internal.net.http; import jdk.internal.net.http.common.HttpHeadersBuilder; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.annotations.AfterClass; import java.lang.ref.Reference; import java.net.Authenticator; @@ -55,12 +52,15 @@ import static java.util.stream.Collectors.joining; import static java.net.http.HttpClient.Version.HTTP_1_1; import static java.net.http.HttpClient.Version.HTTP_2; import static java.net.http.HttpClient.Builder.NO_PROXY; -import static org.testng.Assert.*; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; public class AuthenticationFilterTest { - @DataProvider(name = "uris") - public Object[][] responses() { + public static Object[][] responses() { return new Object[][] { { "http://foo.com", HTTP_1_1, null }, { "http://foo.com", HTTP_2, null }, @@ -135,7 +135,8 @@ public class AuthenticationFilterTest { return s == null || s.isEmpty(); } - @Test(dataProvider = "uris") + @ParameterizedTest + @MethodSource("responses") public void testAuthentication(String uri, Version v, String proxy) throws Exception { String test = format("testAuthentication: {\"%s\", %s, \"%s\"}", uri, v, proxy); try { @@ -146,8 +147,8 @@ public class AuthenticationFilterTest { } } - @AfterClass - public void printDiagnostic() { + @AfterAll + public static void printDiagnostic() { if (FAILED.isEmpty()) { out.println("All tests passed"); return; @@ -183,7 +184,7 @@ public class AuthenticationFilterTest { HttpClientImpl client = facade.impl; AuthenticationFilter filter = new AuthenticationFilter(); - assertEquals(authenticator.COUNTER.get(), 0); + assertEquals(0, authenticator.COUNTER.get()); // Creates the first HttpRequestImpl, and call filter.request() with // it. The expectation is that the filter will not add any credentials, @@ -202,7 +203,7 @@ public class AuthenticationFilterTest { HttpHeaders hdrs = req.getSystemHeadersBuilder().build(); assertFalse(hdrs.firstValue(authorization(true)).isPresent()); assertFalse(hdrs.firstValue(authorization(false)).isPresent()); - assertEquals(authenticator.COUNTER.get(), 0); + assertEquals(0, authenticator.COUNTER.get()); // Creates the Response to the first request, and call filter.response // with it. That response has a 401 or 407 status code. @@ -221,9 +222,9 @@ public class AuthenticationFilterTest { out.println("Checking filter's response to " + unauthorized + " from " + uri); - assertTrue(next != null, "next should not be null"); + assertNotNull(next, "next should not be null"); String[] up = check(reqURI, next.getSystemHeadersBuilder().build(), proxy); - assertEquals(authenticator.COUNTER.get(), 1); + assertEquals(1, authenticator.COUNTER.get()); // Now simulate a new successful exchange to get the credentials in the cache // We first call filter.request with the request that was previously @@ -241,8 +242,8 @@ public class AuthenticationFilterTest { HttpHeaders h = HttpHeaders.of(Collections.emptyMap(), ACCEPT_ALL); response = new Response(next, exchange,h, null, 200, v); next = filter.response(response); - assertTrue(next == null, "next should be null"); - assertEquals(authenticator.COUNTER.get(), 1); + assertNull(next, "next should be null"); + assertEquals(1, authenticator.COUNTER.get()); // Now verify that the cache is used for the next request to the same server. // We're going to create a request to the same server by appending "/bar" to @@ -270,7 +271,7 @@ public class AuthenticationFilterTest { + " with proxy " + req2.proxy()); String[] up2 = check(reqURI, req2.getSystemHeadersBuilder().build(), proxy); assertTrue(Arrays.deepEquals(up, up2), format("%s:%s != %s:%s", up2[0], up2[1], up[0], up[1])); - assertEquals(authenticator.COUNTER.get(), 1); + assertEquals(1, authenticator.COUNTER.get()); // Now verify that the cache is not used if we send a request to a different server. // We're going to append ".bar" to the original request host name, and feed that @@ -316,7 +317,7 @@ public class AuthenticationFilterTest { java.util.stream.Stream.of(getAuthorization(h3, false)) .collect(joining(":"))); assertFalse(h3.firstValue(authorization(false)).isPresent()); - assertEquals(authenticator.COUNTER.get(), 1); + assertEquals(1, authenticator.COUNTER.get()); // Now we will verify that credentials for proxies are not used for servers and // conversely. @@ -365,7 +366,7 @@ public class AuthenticationFilterTest { String[] up4 = check(reqURI, h4, proxy); assertTrue(Arrays.deepEquals(up, up4), format("%s:%s != %s:%s", up4[0], up4[1], up[0], up[1])); } - assertEquals(authenticator.COUNTER.get(), 1); + assertEquals(1, authenticator.COUNTER.get()); if (proxy != null) { // Now if we were using a proxy, we're going to send the same request than @@ -380,7 +381,7 @@ public class AuthenticationFilterTest { MultiExchange multi5 = new MultiExchange(origReq5, req5, client, HttpResponse.BodyHandlers.replacing(null), null); out.println("Simulating new request to " + reqURI + " with a proxy " + req5.proxy()); - assertTrue(req5.proxy() == null, "req5.proxy() should be null"); + assertNull(req5.proxy(), "req5.proxy() should be null"); Exchange exchange5 = new Exchange<>(req5, multi5); filter.request(req5, multi5); out.println("Check that filter has not added server credentials from cache for " @@ -398,7 +399,7 @@ public class AuthenticationFilterTest { java.util.stream.Stream.of(getAuthorization(h5, true)) .collect(joining(":"))); assertFalse(h5.firstValue(authorization(true)).isPresent()); - assertEquals(authenticator.COUNTER.get(), 1); + assertEquals(1, authenticator.COUNTER.get()); // Now simulate a 401 response from the server HttpHeadersBuilder headers5Builder = new HttpHeadersBuilder(); @@ -410,11 +411,11 @@ public class AuthenticationFilterTest { out.println("Simulating " + unauthorized + " response from " + uri); HttpRequestImpl next5 = filter.response(response5); - assertEquals(authenticator.COUNTER.get(), 2); + assertEquals(2, authenticator.COUNTER.get()); out.println("Checking filter's response to " + unauthorized + " from " + uri); - assertTrue(next5 != null, "next5 should not be null"); + assertNotNull(next5, "next5 should not be null"); String[] up5 = check(reqURI, next5.getSystemHeadersBuilder().build(), null); // now simulate a 200 response from the server @@ -423,7 +424,7 @@ public class AuthenticationFilterTest { h = HttpHeaders.of(Map.of(), ACCEPT_ALL); response5 = new Response(next5, exchange5, h, null, 200, v); filter.response(response5); - assertEquals(authenticator.COUNTER.get(), 2); + assertEquals(2, authenticator.COUNTER.get()); // now send the request again, with proxy this time, and it should have both // server auth and proxy auth @@ -433,7 +434,7 @@ public class AuthenticationFilterTest { MultiExchange multi6 = new MultiExchange(origReq6, req6, client, HttpResponse.BodyHandlers.replacing(null), null); out.println("Simulating new request to " + reqURI + " with a proxy " + req6.proxy()); - assertTrue(req6.proxy() != null, "req6.proxy() should not be null"); + assertNotNull(req6.proxy(), "req6.proxy() should not be null"); Exchange exchange6 = new Exchange<>(req6, multi6); filter.request(req6, multi6); out.println("Check that filter has added server credentials from cache for " @@ -444,7 +445,7 @@ public class AuthenticationFilterTest { + reqURI + " (proxy: " + req6.proxy() + ")"); String[] up6 = check(reqURI, h6, proxy); assertTrue(Arrays.deepEquals(up, up6), format("%s:%s != %s:%s", up6[0], up6[1], up[0], up[1])); - assertEquals(authenticator.COUNTER.get(), 2); + assertEquals(2, authenticator.COUNTER.get()); } if (proxy == null && uri.contains("x/y/z")) { @@ -456,7 +457,7 @@ public class AuthenticationFilterTest { MultiExchange multi7 = new MultiExchange(origReq7, req7, client, HttpResponse.BodyHandlers.replacing(null), null); out.println("Simulating new request to " + reqURI7 + " with a proxy " + req7.proxy()); - assertTrue(req7.proxy() == null, "req7.proxy() should be null"); + assertNull(req7.proxy(), "req7.proxy() should be null"); Exchange exchange7 = new Exchange<>(req7, multi7); filter.request(req7, multi7); out.println("Check that filter has not added server credentials from cache for " @@ -475,7 +476,7 @@ public class AuthenticationFilterTest { java.util.stream.Stream.of(getAuthorization(h7, true)) .collect(joining(":"))); assertFalse(h7.firstValue(authorization(true)).isPresent()); - assertEquals(authenticator.COUNTER.get(), 1); + assertEquals(1, authenticator.COUNTER.get()); } @@ -516,7 +517,7 @@ public class AuthenticationFilterTest { out.println("user:password: " + u + ":" + p); String protocol = proxy != null ? "http" : reqURI.getScheme(); String expectedUser = "u." + protocol; - assertEquals(u, expectedUser); + assertEquals(expectedUser, u); String host = proxy == null ? reqURI.getHost() : proxy.substring(0, proxy.lastIndexOf(':')); int port = proxy == null ? reqURI.getPort() @@ -524,7 +525,7 @@ public class AuthenticationFilterTest { String expectedPw = concat(requestorType(proxy!=null), "basic", protocol, host, port, "earth", reqURI.toURL()); - assertEquals(p, expectedPw); + assertEquals(expectedPw, p); return new String[] {u, p}; } diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DefaultProxy.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DefaultProxy.java index 96d08ae2c34..819b02e7fc7 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DefaultProxy.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/DefaultProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,9 @@ import java.net.ProxySelector; import java.net.URI; import java.net.http.HttpClient; import java.util.List; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class DefaultProxy { @@ -42,7 +43,7 @@ public class DefaultProxy { public void testDefault() { ProxySelector ps = getProxySelector(); System.out.println("HttpClientImpl proxySelector:" + ps); - assertEquals(ps, ProxySelector.getDefault()); + assertEquals(ProxySelector.getDefault(), ps); } // From the test driver @@ -56,21 +57,21 @@ public class DefaultProxy { URI uri = URI.create("http://foo.com/example.html"); List plist = ps.select(uri); System.out.println("proxy list for " + uri + " : " + plist); - assertEquals(plist.size(), 1); + assertEquals(1, plist.size()); Proxy proxy = plist.get(0); - assertEquals(proxy.type(), Proxy.Type.HTTP); + assertEquals(Proxy.Type.HTTP, proxy.type()); InetSocketAddress expectedAddr = InetSocketAddress.createUnresolved("foo.proxy.com", 9876); - assertEquals(proxy.address(), expectedAddr); + assertEquals(expectedAddr, proxy.address()); // nonProxyHosts uri = URI.create("http://foo.direct.com/example.html"); plist = ps.select(uri); System.out.println("proxy list for " + uri + " : " + plist); - assertEquals(plist.size(), 1); + assertEquals(1, plist.size()); proxy = plist.get(0); - assertEquals(proxy.type(), Proxy.Type.DIRECT); - assertEquals(proxy.address(), null); + assertEquals(Proxy.Type.DIRECT, proxy.type()); + assertEquals(null, proxy.address()); } // From the test driver @@ -83,21 +84,21 @@ public class DefaultProxy { URI uri = URI.create("https://foo.com/example.html"); List plist = ps.select(uri); System.out.println("proxy list for " + uri + " : " + plist); - assertEquals(plist.size(), 1); + assertEquals(1, plist.size()); Proxy proxy = plist.get(0); - assertEquals(proxy.type(), Proxy.Type.HTTP); + assertEquals(Proxy.Type.HTTP, proxy.type()); InetSocketAddress expectedAddr = InetSocketAddress.createUnresolved("secure.proxy.com", 5443); - assertEquals(proxy.address(), expectedAddr); + assertEquals(expectedAddr, proxy.address()); // nonProxyHosts uri = URI.create("https://foo.direct.com/example.html"); plist = ps.select(uri); System.out.println("proxy list for " + uri + " : " + plist); - assertEquals(plist.size(), 1); + assertEquals(1, plist.size()); proxy = plist.get(0); - assertEquals(proxy.type(), Proxy.Type.DIRECT); - assertEquals(proxy.address(), null); + assertEquals(Proxy.Type.DIRECT, proxy.type()); + assertEquals(null, proxy.address()); } } diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/FlowTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/FlowTest.java index 3e9e967c061..cd05196b653 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/FlowTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/FlowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,6 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.util.List; -import java.util.Random; -import java.util.StringTokenizer; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; @@ -47,10 +45,10 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import javax.net.ssl.*; import jdk.internal.net.http.common.Utils; -import org.testng.annotations.Test; import jdk.internal.net.http.common.SSLFlowDelegate; -@Test +import org.junit.jupiter.api.Test; + public class FlowTest extends AbstractRandomTest { private final SubmissionPublisher> srcPublisher; @@ -241,7 +239,7 @@ public class FlowTest extends AbstractRandomTest { private void clientReader() { try { InputStream is = clientSock.getInputStream(); - final int bufsize = FlowTest.randomRange(512, 16 * 1024); + final int bufsize = AbstractRandomTest.randomRange(512, 16 * 1024); println("clientReader: bufsize = " + bufsize); while (true) { byte[] buf = new byte[bufsize]; @@ -315,8 +313,8 @@ public class FlowTest extends AbstractRandomTest { private final AtomicInteger loopCount = new AtomicInteger(); public String monitor() { - return "serverLoopback: loopcount = " + loopCount.toString() - + " clientRead: count = " + readCount.toString(); + return "serverLoopback: loopcount = " + loopCount.get() + + " clientRead: count = " + readCount.get(); } // thread2 @@ -324,7 +322,7 @@ public class FlowTest extends AbstractRandomTest { try { InputStream is = serverSock.getInputStream(); OutputStream os = serverSock.getOutputStream(); - final int bufsize = FlowTest.randomRange(512, 16 * 1024); + final int bufsize = AbstractRandomTest.randomRange(512, 16 * 1024); println("serverLoopback: bufsize = " + bufsize); byte[] bb = new byte[bufsize]; while (true) { diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/Http1HeaderParserTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/Http1HeaderParserTest.java index 9bde9109095..a4c7b76aba8 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/Http1HeaderParserTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/Http1HeaderParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,22 +36,22 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.IntStream; import sun.net.www.MessageHeader; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; import static java.lang.System.out; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.US_ASCII; import static java.util.stream.Collectors.toList; -import static org.testng.Assert.*; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; // Mostly verifies the "new" Http1HeaderParser returns the same results as the // tried and tested sun.net.www.MessageHeader. public class Http1HeaderParserTest { - @DataProvider(name = "responses") - public Object[][] responses() { + public static Object[][] responses() { List responses = new ArrayList<>(); String[] basic = @@ -316,7 +316,8 @@ public class Http1HeaderParserTest { } - @Test(dataProvider = "responses") + @ParameterizedTest + @MethodSource("responses") public void verifyHeaders(String respString) throws Exception { System.out.println("\ntesting:\n\t" + respString .replace("\r\n", "") @@ -339,7 +340,7 @@ public class Http1HeaderParserTest { String statusLine1 = messageHeaderMap.get(null).get(0); String statusLine2 = decoder.statusLine(); if (statusLine1.startsWith("HTTP")) {// skip the case where MH's messes up the status-line - assertEquals(statusLine2, statusLine1, "Status-line not equal"); + assertEquals(statusLine1, statusLine2, "Status-line not equal"); } else { assertTrue(statusLine2.startsWith("HTTP/1."), "Status-line not HTTP/1."); } @@ -356,7 +357,7 @@ public class Http1HeaderParserTest { assertHeadersEqual(messageHeaderMap, decoderMap1, "messageHeaderMap not equal to decoderMap1"); - assertEquals(availableBytes, b.remaining(), + assertEquals(b.remaining(), availableBytes, String.format("stream available (%d) not equal to remaining (%d)", availableBytes, b.remaining())); // byte at a time @@ -366,14 +367,13 @@ public class Http1HeaderParserTest { .collect(toList()); while (decoder.parse(buffers.remove(0)) != true); Map> decoderMap2 = decoder.headers().map(); - assertEquals(availableBytes, buffers.size(), + assertEquals(buffers.size(), availableBytes, "stream available not equals to remaining buffers"); - assertEquals(decoderMap1, decoderMap2, "decoder maps not equal"); + assertEquals(decoderMap2, decoderMap1, "decoder maps not equal"); } - @DataProvider(name = "errors") - public Object[][] errors() { + public static Object[][] errors() { List responses = new ArrayList<>(); // These responses are parsed, somewhat, by MessageHeaders but give @@ -451,12 +451,15 @@ public class Http1HeaderParserTest { return responses.stream().map(p -> new Object[] { p }).toArray(Object[][]::new); } - @Test(dataProvider = "errors", expectedExceptions = ProtocolException.class) + @ParameterizedTest + @MethodSource("errors") public void errors(String respString) throws ProtocolException { - byte[] bytes = respString.getBytes(US_ASCII); - Http1HeaderParser decoder = new Http1HeaderParser(); - ByteBuffer b = ByteBuffer.wrap(bytes); - decoder.parse(b); + assertThrows(ProtocolException.class, () -> { + byte[] bytes = respString.getBytes(US_ASCII); + Http1HeaderParser decoder = new Http1HeaderParser(); + ByteBuffer b = ByteBuffer.wrap(bytes); + decoder.parse(b); + }); } void assertHeadersEqual(Map> expected, @@ -466,7 +469,7 @@ public class Http1HeaderParserTest { if (expected.equals(actual)) return; - assertEquals(expected.size(), actual.size(), + assertEquals(actual.size(), expected.size(), format("%s. Expected size %d, actual size %s. %nexpected= %s,%n actual=%s.", msg, expected.size(), actual.size(), mapToString(expected), mapToString(actual))); @@ -479,7 +482,7 @@ public class Http1HeaderParserTest { if (key.equalsIgnoreCase(other.getKey())) { found = true; List otherValues = other.getValue(); - assertEquals(values.size(), otherValues.size(), + assertEquals(otherValues.size(), values.size(), format("%s. Expected list size %d, actual size %s", msg, values.size(), otherValues.size())); if (!(values.containsAll(otherValues) && otherValues.containsAll(values))) @@ -508,11 +511,11 @@ public class Http1HeaderParserTest { public static void main(String... args) throws Exception { Http1HeaderParserTest test = new Http1HeaderParserTest(); int count = 0; - for (Object[] objs : test.responses()) { + for (Object[] objs : Http1HeaderParserTest.responses()) { out.println("Testing " + count++ + ", " + objs[0]); test.verifyHeaders((String) objs[0]); } - for (Object[] objs : test.errors()) { + for (Object[] objs : Http1HeaderParserTest.errors()) { out.println("Testing " + count++ + ", " + objs[0]); try { test.errors((String) objs[0]); diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/RawChannelTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/RawChannelTest.java index f6bcdcb4d33..62ca237d2f1 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/RawChannelTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/RawChannelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,10 +47,11 @@ import java.net.http.HttpResponse; import java.util.concurrent.atomic.AtomicReference; import jdk.internal.net.http.websocket.RawChannel; -import org.testng.annotations.Test; import static java.net.http.HttpResponse.BodyHandlers.discarding; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.testng.Assert.assertEquals; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /* * This test exercises mechanics of _independent_ reads and writes on the @@ -222,8 +223,8 @@ public class RawChannelTest { closeChannel(chan); }); exit.await(); // All done, we need to compare results: - assertEquals(clientRead.get(), serverWritten.get()); - assertEquals(serverRead.get(), clientWritten.get()); + assertEquals(serverWritten.get(), clientRead.get()); + assertEquals(clientWritten.get(), serverRead.get()); Throwable serverError = testServer.failed.get(); if (serverError != null) { throw new AssertionError("TestServer failed: " diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLEchoTubeTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLEchoTubeTest.java index 2884b74eee5..4316a46a25c 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLEchoTubeTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLEchoTubeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import jdk.internal.net.http.common.FlowTube; import jdk.internal.net.http.common.SSLTube; import jdk.internal.net.http.common.SequentialScheduler; import jdk.internal.net.http.common.Utils; -import org.testng.annotations.Test; import java.io.IOException; import java.nio.ByteBuffer; @@ -44,7 +43,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -@Test +import org.junit.jupiter.api.Test; + public class SSLEchoTubeTest extends AbstractSSLTubeTest { @Test diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLFlowDelegateTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLFlowDelegateTest.java index 6b031bdfa58..32511de173b 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLFlowDelegateTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLFlowDelegateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,10 +58,11 @@ import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.SSLFlowDelegate; import jdk.internal.net.http.common.SubscriberWrapper; import jdk.internal.net.http.common.Utils; -import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; // jtreg test definition for this test resides in SSLFlowDelegateTestDriver.java public class SSLFlowDelegateTest { @@ -70,38 +71,38 @@ public class SSLFlowDelegateTest { private static final Random random = new Random(); private static final byte DATA_BYTE = (byte) random.nextInt(); - private ExecutorService executor; - private SSLParameters sslParams; - private SSLServerSocket sslServerSocket; - private SSLEngine clientEngine; - private CompletableFuture testCompletion; + private static ExecutorService executor; + private static SSLParameters sslParams; + private static SSLServerSocket sslServerSocket; + private static SSLEngine clientEngine; + private static CompletableFuture testCompletion; - @BeforeTest - public void beforeTest() throws Exception { - this.executor = Executors.newCachedThreadPool(); - this.testCompletion = new CompletableFuture<>(); + @BeforeAll + public static void beforeTest() throws Exception { + executor = Executors.newCachedThreadPool(); + testCompletion = new CompletableFuture<>(); final SSLParameters sp = new SSLParameters(); sp.setApplicationProtocols(new String[]{ALPN}); - this.sslParams = sp; + sslParams = sp; var sslContext = SimpleSSLContextWhiteboxAdapter.findSSLContext(); - this.sslServerSocket = startServer(sslContext); - println(debugTag, "Server started at " + this.sslServerSocket.getInetAddress() + ":" - + this.sslServerSocket.getLocalPort()); + sslServerSocket = startServer(sslContext); + println(debugTag, "Server started at " + sslServerSocket.getInetAddress() + ":" + + sslServerSocket.getLocalPort()); - this.clientEngine = createClientEngine(sslContext); + clientEngine = createClientEngine(sslContext); } - @AfterTest - public void afterTest() throws Exception { - if (this.sslServerSocket != null) { - println(debugTag, "Closing server socket " + this.sslServerSocket); - this.sslServerSocket.close(); + @AfterAll + public static void afterTest() throws Exception { + if (sslServerSocket != null) { + println(debugTag, "Closing server socket " + sslServerSocket); + sslServerSocket.close(); } - if (this.executor != null) { - println(debugTag, "Shutting down the executor " + this.executor); - this.executor.shutdownNow(); + if (executor != null) { + println(debugTag, "Shutting down the executor " + executor); + executor.shutdownNow(); } } @@ -117,30 +118,30 @@ public class SSLFlowDelegateTest { } } - private SSLServerSocket createSSLServerSocket( + private static SSLServerSocket createSSLServerSocket( final SSLContext ctx, final InetSocketAddress bindAddr) throws IOException { final SSLServerSocketFactory fac = ctx.getServerSocketFactory(); final SSLServerSocket sslServerSocket = (SSLServerSocket) fac.createServerSocket(); sslServerSocket.setReuseAddress(false); - sslServerSocket.setSSLParameters(this.sslParams); + sslServerSocket.setSSLParameters(sslParams); sslServerSocket.bind(bindAddr); return sslServerSocket; } - private SSLServerSocket startServer(final SSLContext ctx) throws Exception { + private static SSLServerSocket startServer(final SSLContext ctx) throws Exception { final SSLServerSocket sslServerSocket = createSSLServerSocket(ctx, new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); final Runnable serverResponsePusher = new ServerResponsePusher(sslServerSocket, - this.testCompletion); + testCompletion); final Thread serverThread = new Thread(serverResponsePusher, "serverResponsePusher"); // start the thread which will accept() a socket connection and send data over it serverThread.start(); return sslServerSocket; } - private SSLEngine createClientEngine(final SSLContext ctx) { + private static SSLEngine createClientEngine(final SSLContext ctx) { final SSLEngine clientEngine = ctx.createSSLEngine(); - clientEngine.setSSLParameters(this.sslParams); + clientEngine.setSSLParameters(sslParams); clientEngine.setUseClientMode(true); return clientEngine; } @@ -170,7 +171,7 @@ public class SSLFlowDelegateTest { // in various places in this test. If the "testCompletion" completes before // the "soleExpectedAppData" completes (typically due to some exception), // then we complete the "soleExpectedAppData" too. - this.testCompletion.whenComplete((r, t) -> { + testCompletion.whenComplete((r, t) -> { if (soleExpectedAppData.isDone()) { return; } @@ -221,7 +222,7 @@ public class SSLFlowDelegateTest { println(debugTag, "Waiting for handshake to complete"); final String negotiatedALPN = sslFlowDelegate.alpn().join(); println(debugTag, "handshake completed, with negotiated ALPN: " + negotiatedALPN); - Assert.assertEquals(negotiatedALPN, ALPN, "unexpected ALPN negotiated"); + assertEquals(ALPN, negotiatedALPN, "unexpected ALPN negotiated"); try { // now wait for the initial (and the only) chunk of application data to be // received by the AppResponseReceiver @@ -254,7 +255,7 @@ public class SSLFlowDelegateTest { private void failTest(final CompletionException ce) { final Throwable cause = ce.getCause(); - Assert.fail(cause.getMessage() == null ? "test failed" : cause.getMessage(), cause); + fail(cause.getMessage() == null ? "test failed" : cause.getMessage(), cause); } // uses reflection to get hold of the SSLFlowDelegate.reader.outputQ member field, @@ -288,7 +289,7 @@ public class SSLFlowDelegateTest { } println(debugTag, "num unsolicited bytes so far = " + numUnsolicitated); } - Assert.assertEquals(numUnsolicitated, 0, + assertEquals(0, numUnsolicitated, "SSLFlowDelegate has accumulated " + numUnsolicitated + " unsolicited bytes"); } diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java index ac6a235b8e2..bb8d583e07b 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package jdk.internal.net.http; import jdk.internal.net.http.common.FlowTube; import jdk.internal.net.http.common.SSLFlowDelegate; import jdk.internal.net.http.common.Utils; -import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; @@ -51,7 +50,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.SubmissionPublisher; import java.util.concurrent.atomic.AtomicInteger; -@Test +import org.junit.jupiter.api.Test; + public class SSLTubeTest extends AbstractSSLTubeTest { @Test @@ -125,7 +125,7 @@ public class SSLTubeTest extends AbstractSSLTubeTest { private void clientReader() { try { InputStream is = clientSock.getInputStream(); - final int bufsize = randomRange(512, 16 * 1024); + final int bufsize = AbstractRandomTest.randomRange(512, 16 * 1024); System.out.println("clientReader: bufsize = " + bufsize); while (true) { byte[] buf = new byte[bufsize]; @@ -137,7 +137,7 @@ public class SSLTubeTest extends AbstractSSLTubeTest { allBytesReceived.await(); System.out.println("clientReader: closing publisher"); publisher.close(); - sleep(2000); + AbstractSSLTubeTest.sleep(2000); Utils.close(is, clientSock); return; } @@ -206,13 +206,13 @@ public class SSLTubeTest extends AbstractSSLTubeTest { try { InputStream is = serverSock.getInputStream(); OutputStream os = serverSock.getOutputStream(); - final int bufsize = randomRange(512, 16 * 1024); + final int bufsize = AbstractRandomTest.randomRange(512, 16 * 1024); System.out.println("serverLoopback: bufsize = " + bufsize); byte[] bb = new byte[bufsize]; while (true) { int n = is.read(bb); if (n == -1) { - sleep(2000); + AbstractSSLTubeTest.sleep(2000); is.close(); os.close(); serverSock.close(); diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SelectorTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SelectorTest.java index 5b8da3b9979..3027df0436e 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SelectorTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SelectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,20 +31,20 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.net.http.HttpClient; import java.net.http.HttpResponse; -import org.testng.annotations.Test; import jdk.internal.net.http.websocket.RawChannel; import static java.lang.System.out; import static java.nio.charset.StandardCharsets.US_ASCII; import static java.util.concurrent.TimeUnit.SECONDS; import static java.net.http.HttpResponse.BodyHandlers.discarding; +import org.junit.jupiter.api.Test; + /** * Whitebox test of selector mechanics. Currently only a simple test * setting one read and one write event is done. It checks that the * write event occurs first, followed by the read event and then no * further events occur despite the conditions actually still existing. */ -@Test public class SelectorTest { AtomicInteger counter = new AtomicInteger(); diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WindowControllerTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WindowControllerTest.java index 0a94f471575..5df3b4227e6 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WindowControllerTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WindowControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,92 +23,93 @@ package jdk.internal.net.http; -import org.testng.annotations.Test; import static jdk.internal.net.http.frame.SettingsFrame.DEFAULT_INITIAL_WINDOW_SIZE; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class WindowControllerTest { @Test public void testConnectionWindowOverflow() { WindowController wc = new WindowController(); - assertEquals(wc.connectionWindowSize(), DEFAULT_INITIAL_WINDOW_SIZE); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.connectionWindowSize(), DEFAULT_INITIAL_WINDOW_SIZE); + assertEquals(DEFAULT_INITIAL_WINDOW_SIZE, wc.connectionWindowSize()); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(DEFAULT_INITIAL_WINDOW_SIZE, wc.connectionWindowSize()); wc.registerStream(1, DEFAULT_INITIAL_WINDOW_SIZE); wc.tryAcquire(DEFAULT_INITIAL_WINDOW_SIZE - 1, 1, null); - assertEquals(wc.connectionWindowSize(), 1); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.connectionWindowSize(), 1); + assertEquals(1, wc.connectionWindowSize()); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(1, wc.connectionWindowSize()); wc.increaseConnectionWindow(Integer.MAX_VALUE - 1 -1); - assertEquals(wc.connectionWindowSize(), Integer.MAX_VALUE - 1); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.connectionWindowSize(), Integer.MAX_VALUE - 1); + assertEquals(Integer.MAX_VALUE - 1, wc.connectionWindowSize()); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(Integer.MAX_VALUE - 1, wc.connectionWindowSize()); wc.increaseConnectionWindow(1); - assertEquals(wc.connectionWindowSize(), Integer.MAX_VALUE); - assertEquals(wc.increaseConnectionWindow(1), false); - assertEquals(wc.increaseConnectionWindow(100), false); - assertEquals(wc.increaseConnectionWindow(Integer.MAX_VALUE), false); - assertEquals(wc.connectionWindowSize(), Integer.MAX_VALUE); + assertEquals(Integer.MAX_VALUE, wc.connectionWindowSize()); + assertEquals(false, wc.increaseConnectionWindow(1)); + assertEquals(false, wc.increaseConnectionWindow(100)); + assertEquals(false, wc.increaseConnectionWindow(Integer.MAX_VALUE)); + assertEquals(Integer.MAX_VALUE, wc.connectionWindowSize()); } @Test public void testStreamWindowOverflow() { WindowController wc = new WindowController(); wc.registerStream(1, DEFAULT_INITIAL_WINDOW_SIZE); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 1), false); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 1), false); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 1), false); + assertEquals(false, wc.increaseStreamWindow(Integer.MAX_VALUE, 1)); + assertEquals(false, wc.increaseStreamWindow(Integer.MAX_VALUE, 1)); + assertEquals(false, wc.increaseStreamWindow(Integer.MAX_VALUE, 1)); wc.registerStream(3, DEFAULT_INITIAL_WINDOW_SIZE); - assertEquals(wc.increaseStreamWindow(100, 3), true); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 3), false); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 3), false); + assertEquals(true, wc.increaseStreamWindow(100, 3)); + assertEquals(false, wc.increaseStreamWindow(Integer.MAX_VALUE, 3)); + assertEquals(false, wc.increaseStreamWindow(Integer.MAX_VALUE, 3)); wc.registerStream(5, 0); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 5), true); - assertEquals(wc.increaseStreamWindow(1, 5), false); - assertEquals(wc.increaseStreamWindow(1, 5), false); - assertEquals(wc.increaseStreamWindow(10, 5), false); + assertEquals(true, wc.increaseStreamWindow(Integer.MAX_VALUE, 5)); + assertEquals(false, wc.increaseStreamWindow(1, 5)); + assertEquals(false, wc.increaseStreamWindow(1, 5)); + assertEquals(false, wc.increaseStreamWindow(10, 5)); wc.registerStream(7, -1); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 7), true); - assertEquals(wc.increaseStreamWindow(1, 7), true); - assertEquals(wc.increaseStreamWindow(1, 7), false); - assertEquals(wc.increaseStreamWindow(10, 7), false); + assertEquals(true, wc.increaseStreamWindow(Integer.MAX_VALUE, 7)); + assertEquals(true, wc.increaseStreamWindow(1, 7)); + assertEquals(false, wc.increaseStreamWindow(1, 7)); + assertEquals(false, wc.increaseStreamWindow(10, 7)); wc.registerStream(9, -1); - assertEquals(wc.increaseStreamWindow(1, 9), true); - assertEquals(wc.increaseStreamWindow(1, 9), true); - assertEquals(wc.increaseStreamWindow(1, 9), true); - assertEquals(wc.increaseStreamWindow(10, 9), true); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 9), false); + assertEquals(true, wc.increaseStreamWindow(1, 9)); + assertEquals(true, wc.increaseStreamWindow(1, 9)); + assertEquals(true, wc.increaseStreamWindow(1, 9)); + assertEquals(true, wc.increaseStreamWindow(10, 9)); + assertEquals(false, wc.increaseStreamWindow(Integer.MAX_VALUE, 9)); wc.registerStream(11, -10); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.increaseStreamWindow(1, 11), true); - assertEquals(wc.streamWindowSize(11), 1); - assertEquals(wc.increaseStreamWindow(Integer.MAX_VALUE, 11), false); - assertEquals(wc.streamWindowSize(11), 1); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(true, wc.increaseStreamWindow(1, 11)); + assertEquals(1, wc.streamWindowSize(11)); + assertEquals(false, wc.increaseStreamWindow(Integer.MAX_VALUE, 11)); + assertEquals(1, wc.streamWindowSize(11)); } @Test @@ -125,9 +126,9 @@ public class WindowControllerTest { wc.tryAcquire(51, 5 , null); wc.adjustActiveStreams(-200); - assertEquals(wc.streamWindowSize(1), -149); - assertEquals(wc.streamWindowSize(3), -150); - assertEquals(wc.streamWindowSize(5), -151); + assertEquals(-149, wc.streamWindowSize(1)); + assertEquals(-150, wc.streamWindowSize(3)); + assertEquals(-151, wc.streamWindowSize(5)); } static final Class IE = InternalError.class; diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WrapperTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WrapperTest.java index 6dad2cc75b5..bc69c425678 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WrapperTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/WrapperTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,10 @@ import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import org.testng.annotations.Test; import jdk.internal.net.http.common.SubscriberWrapper; -@Test +import org.junit.jupiter.api.Test; + public class WrapperTest { static final int LO_PRI = 1; static final int HI_PRI = 2; diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/DemandTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/DemandTest.java index 4ea604fd488..1ea72f472e9 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/DemandTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/DemandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,16 @@ package jdk.internal.net.http.common; -import org.testng.annotations.Test; - import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.AtomicReference; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DemandTest { @@ -59,53 +60,61 @@ public class DemandTest { public void test03() { Demand d = new Demand(); d.increase(3); - assertEquals(d.decreaseAndGet(3), 3); + assertEquals(3, d.decreaseAndGet(3)); } @Test public void test04() { Demand d = new Demand(); d.increase(3); - assertEquals(d.decreaseAndGet(5), 3); + assertEquals(3, d.decreaseAndGet(5)); } @Test public void test05() { Demand d = new Demand(); d.increase(7); - assertEquals(d.decreaseAndGet(4), 4); + assertEquals(4, d.decreaseAndGet(4)); } @Test public void test06() { Demand d = new Demand(); - assertEquals(d.decreaseAndGet(3), 0); + assertEquals(0, d.decreaseAndGet(3)); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test07() { - Demand d = new Demand(); - d.increase(0); + assertThrows(IllegalArgumentException.class, () -> { + Demand d = new Demand(); + d.increase(0); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test08() { - Demand d = new Demand(); - d.increase(-1); + assertThrows(IllegalArgumentException.class, () -> { + Demand d = new Demand(); + d.increase(-1); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test09() { - Demand d = new Demand(); - d.increase(10); - d.decreaseAndGet(0); + assertThrows(IllegalArgumentException.class, () -> { + Demand d = new Demand(); + d.increase(10); + d.decreaseAndGet(0); + }); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test10() { - Demand d = new Demand(); - d.increase(13); - d.decreaseAndGet(-3); + assertThrows(IllegalArgumentException.class, () -> { + Demand d = new Demand(); + d.increase(13); + d.decreaseAndGet(-3); + }); } @Test @@ -169,7 +178,7 @@ public class DemandTest { assertTrue(d.isFulfilled()); } - @Test(invocationCount = 32) + @Test public void test15() throws InterruptedException { int N = Math.max(2, Runtime.getRuntime().availableProcessors() + 1); int M = ((N + 1) * N) / 2; // 1 + 2 + 3 + ... N @@ -187,7 +196,7 @@ public class DemandTest { error.compareAndSet(null, e); } try { - assertEquals(d.decreaseAndGet(j), j); + assertEquals(j, d.decreaseAndGet(j)); } catch (Throwable t) { error.compareAndSet(null, t); } finally { @@ -197,6 +206,6 @@ public class DemandTest { } stop.await(); assertTrue(d.isFulfilled()); - assertEquals(error.get(), null); + assertNull(error.get()); } } diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/MinimalFutureTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/MinimalFutureTest.java index 01798a645a2..2c33f6f0018 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/MinimalFutureTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/common/MinimalFutureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,19 +23,19 @@ package jdk.internal.net.http.common; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import static org.testng.Assert.assertThrows; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; public class MinimalFutureTest { - @Test(dataProvider = "futures") + @ParameterizedTest + @MethodSource("futures") public void test(CompletableFuture mf) { ExecutorService executor = Executors.newSingleThreadExecutor(); try { @@ -134,8 +134,7 @@ public class MinimalFutureTest { } - @DataProvider(name = "futures") - public Object[][] futures() { + public static Object[][] futures() { MinimalFuture mf = new MinimalFuture<>(); mf.completeExceptionally(new Throwable()); diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/frame/FramesDecoderTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/frame/FramesDecoderTest.java index 3db439d1c00..e8acc95c1d2 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/frame/FramesDecoderTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/frame/FramesDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,15 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import org.testng.Assert; -import org.testng.annotations.Test; import static java.lang.System.out; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.testng.Assert.*; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; public class FramesDecoderTest { - abstract class TestFrameProcessor implements FramesDecoder.FrameProcessor { + abstract static class TestFrameProcessor implements FramesDecoder.FrameProcessor { protected volatile int count; public int numberOfFramesDecoded() { return count; } } @@ -69,17 +69,17 @@ public class FramesDecoderTest { assertTrue(frame instanceof DataFrame); DataFrame dataFrame = (DataFrame) frame; List list = dataFrame.getData(); - assertEquals(list.size(), 1); + assertEquals(1, list.size()); ByteBuffer data = list.get(0); byte[] bytes = new byte[data.remaining()]; data.get(bytes); if (count == 0) { - assertEquals(new String(bytes, UTF_8), "XXXX"); + assertEquals("XXXX", new String(bytes, UTF_8)); out.println("First data received:" + data); - assertEquals(data.position(), data.limit()); // since bytes read - assertEquals(data.limit(), data.capacity()); + assertEquals(data.limit(), data.position()); // since bytes read + assertEquals(data.capacity(), data.limit()); } else { - assertEquals(new String(bytes, UTF_8), "YYYY"); + assertEquals("YYYY", new String(bytes, UTF_8)); out.println("Second data received:" + data); } count++; @@ -89,7 +89,7 @@ public class FramesDecoderTest { out.println("Sending " + combined + " to decoder: "); decoder.decode(combined); - Assert.assertEquals(testFrameProcessor.numberOfFramesDecoded(), 2); + assertEquals(2, testFrameProcessor.numberOfFramesDecoded()); } @@ -119,15 +119,15 @@ public class FramesDecoderTest { assertTrue(frame instanceof DataFrame); DataFrame dataFrame = (DataFrame) frame; List list = dataFrame.getData(); - assertEquals(list.size(), 1); + assertEquals(1, list.size()); ByteBuffer data = list.get(0); byte[] bytes = new byte[data.remaining()]; data.get(bytes); - assertEquals(new String(bytes, UTF_8), "XXXX"); + assertEquals("XXXX", new String(bytes, UTF_8)); out.println("First data received:" + data); - assertEquals(data.position(), data.limit()); // since bytes read + assertEquals(data.limit(), data.position()); // since bytes read //assertNotEquals(data.limit(), data.capacity()); - assertEquals(data.capacity(), 1024 - 9 /*frame header*/); + assertEquals(1024 - 9 /*frame header*/, data.capacity()); count++; } }; @@ -135,6 +135,6 @@ public class FramesDecoderTest { out.println("Sending " + combined + " to decoder: "); decoder.decode(combined); - Assert.assertEquals(testFrameProcessor.numberOfFramesDecoded(), 1); + assertEquals(1, testFrameProcessor.numberOfFramesDecoded()); } } From a0c0a3617936bb024ee7a9325b98a49ccaab5041 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 5 Mar 2026 11:12:58 +0000 Subject: [PATCH 053/655] 8378600: Refactor tests under test/jdk/java/net/httpclient/http2 from TestNG to JUnit Reviewed-by: vyazici --- .../java/net/httpclient/http2/ErrorTest.java | 4 +- .../httpclient/http2/FixedThreadPoolTest.java | 6 +- .../httpclient/http2/H2SelectorVTTest.java | 10 +-- .../httpclient/http2/ImplicitPushCancel.java | 35 +++++---- .../java/net/httpclient/http2/NoBodyTest.java | 10 +-- .../net/httpclient/http2/PostPutTest.java | 36 ++++----- .../http2/PushPromiseContinuation.java | 49 ++++++------ .../net/httpclient/http2/RedirectTest.java | 7 +- .../java/net/httpclient/http2/ServerPush.java | 61 ++++++++------- .../http2/ServerPushWithDiffTypes.java | 15 ++-- .../java/net/httpclient/http2/SimpleGet.java | 21 ++--- .../http2/StreamFlowControlTest.java | 78 ++++++++++--------- .../httpclient/http2/TrailingHeadersTest.java | 49 ++++++------ .../net/http/hpack/HeaderTableTest.java | 6 +- 14 files changed, 196 insertions(+), 191 deletions(-) diff --git a/test/jdk/java/net/httpclient/http2/ErrorTest.java b/test/jdk/java/net/httpclient/http2/ErrorTest.java index 6b36529b38f..0f3bafa571d 100644 --- a/test/jdk/java/net/httpclient/http2/ErrorTest.java +++ b/test/jdk/java/net/httpclient/http2/ErrorTest.java @@ -45,7 +45,7 @@ * java.net.http/jdk.internal.net.http.qpack.writers * java.security.jgss * @modules java.base/jdk.internal.util - * @run testng/othervm/timeout=60 -Djavax.net.debug=ssl -Djdk.httpclient.HttpClient.log=all ErrorTest + * @run junit/othervm/timeout=60 -Djavax.net.debug=ssl -Djdk.httpclient.HttpClient.log=all ErrorTest * @summary check exception thrown when bad TLS parameters selected */ @@ -67,7 +67,7 @@ import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.test.lib.net.SimpleSSLContext; import static java.net.http.HttpClient.Version.HTTP_2; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; /** * When selecting an unacceptable cipher suite the TLS handshake will fail. diff --git a/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java b/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java index 2378b0b6982..d788d39b441 100644 --- a/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java +++ b/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java @@ -30,7 +30,7 @@ * jdk.test.lib.Asserts * jdk.test.lib.Utils * jdk.test.lib.net.SimpleSSLContext - * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors FixedThreadPoolTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors FixedThreadPoolTest */ import java.net.*; @@ -51,7 +51,7 @@ import static jdk.test.lib.Asserts.assertFileContentsEqual; import static jdk.test.lib.Utils.createTempFile; import static jdk.test.lib.Utils.createTempFileOfSize; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; public class FixedThreadPoolTest implements HttpServerAdapters { @@ -92,7 +92,7 @@ public class FixedThreadPoolTest implements HttpServerAdapters { } @Test - public static void test() throws Exception { + public void test() throws Exception { try { initialize(); simpleTest(false); diff --git a/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java b/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java index 85d4012494a..7adfd57319c 100644 --- a/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java +++ b/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java @@ -38,7 +38,7 @@ import jdk.test.lib.net.SimpleSSLContext; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.Version.HTTP_2; @@ -166,21 +166,21 @@ class H2SelectorVTTest implements HttpServerAdapters { final HttpRequest req1 = reqBuilder.copy().GET().build(); System.out.println("\nIssuing request: " + req1); final HttpResponse resp1 = client.send(req1, BodyHandlers.ofString()); - Assertions.assertEquals(200, resp1.statusCode(), "unexpected response code for GET request"); + assertEquals(200, resp1.statusCode(), "unexpected response code for GET request"); assertSelectorThread(client); // POST final HttpRequest req2 = reqBuilder.copy().POST(BodyPublishers.ofString("foo")).build(); System.out.println("\nIssuing request: " + req2); final HttpResponse resp2 = client.send(req2, BodyHandlers.ofString()); - Assertions.assertEquals(200, resp2.statusCode(), "unexpected response code for POST request"); + assertEquals(200, resp2.statusCode(), "unexpected response code for POST request"); assertSelectorThread(client); // HEAD final HttpRequest req3 = reqBuilder.copy().HEAD().build(); System.out.println("\nIssuing request: " + req3); final HttpResponse resp3 = client.send(req3, BodyHandlers.ofString()); - Assertions.assertEquals(200, resp3.statusCode(), "unexpected response code for HEAD request"); + assertEquals(200, resp3.statusCode(), "unexpected response code for HEAD request"); assertSelectorThread(client); } } @@ -219,6 +219,6 @@ class H2SelectorVTTest implements HttpServerAdapters { msg = "%s not found in %s".formatted(name, threads); System.out.printf("%s: %s%n", status, msg); } - Assertions.assertEquals(!isTCPSelectorThreadVirtual(), found, msg); + assertEquals(!isTCPSelectorThreadVirtual(), found, msg); } } diff --git a/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java b/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java index c75a62d0f42..5bcaf95c6fc 100644 --- a/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java +++ b/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses,trace * ImplicitPushCancel @@ -51,15 +51,16 @@ import java.util.concurrent.ConcurrentMap; import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.httpclient.test.lib.http2.Http2TestExchange; import jdk.httpclient.test.lib.http2.Http2Handler; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.testng.Assert.assertEquals; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ImplicitPushCancel { - static Map PUSH_PROMISES = Map.of( + static final Map PUSH_PROMISES = Map.of( "/x/y/z/1", "the first push promise body", "/x/y/z/2", "the second push promise body", "/x/y/z/3", "the third push promise body", @@ -72,11 +73,11 @@ public class ImplicitPushCancel { ); static final String MAIN_RESPONSE_BODY = "the main response body"; - Http2TestServer server; - URI uri; + private static Http2TestServer server; + private static URI uri; - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { server = new Http2TestServer(false, 0); Http2Handler handler = new ServerPushHandler(MAIN_RESPONSE_BODY, PUSH_PROMISES); @@ -87,13 +88,13 @@ public class ImplicitPushCancel { uri = new URI("http://localhost:" + port + "/foo/a/b/c"); } - @AfterTest - public void teardown() { + @AfterAll + public static void teardown() { server.stop(); } static final HttpResponse assert200ResponseCode(HttpResponse response) { - assertEquals(response.statusCode(), 200); + assertEquals(200, response.statusCode()); return response; } @@ -128,11 +129,11 @@ public class ImplicitPushCancel { promises.entrySet().stream().forEach(entry -> { HttpRequest request = entry.getKey(); HttpResponse response = entry.getValue().join(); - assertEquals(response.statusCode(), 200); + assertEquals(200, response.statusCode()); if (PUSH_PROMISES.containsKey(request.uri().getPath())) { - assertEquals(response.body(), PUSH_PROMISES.get(request.uri().getPath())); + assertEquals(PUSH_PROMISES.get(request.uri().getPath()), response.body()); } else { - assertEquals(response.body(), MAIN_RESPONSE_BODY); + assertEquals(MAIN_RESPONSE_BODY, response.body()); } } ); diff --git a/test/jdk/java/net/httpclient/http2/NoBodyTest.java b/test/jdk/java/net/httpclient/http2/NoBodyTest.java index 3d30c54654a..2459c8eba4b 100644 --- a/test/jdk/java/net/httpclient/http2/NoBodyTest.java +++ b/test/jdk/java/net/httpclient/http2/NoBodyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @bug 8087112 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer - * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors + * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true * NoBodyTest */ @@ -47,10 +47,10 @@ import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.httpclient.test.lib.http2.Http2TestExchange; import jdk.httpclient.test.lib.http2.Http2Handler; import jdk.test.lib.net.SimpleSSLContext; -import org.testng.annotations.Test; import static java.net.http.HttpClient.Version.HTTP_2; -@Test +import org.junit.jupiter.api.Test; + public class NoBodyTest { static int httpPort, httpsPort; static Http2TestServer httpServer, httpsServer; @@ -86,7 +86,7 @@ public class NoBodyTest { } @Test - public static void runtest() throws Exception { + public void runtest() throws Exception { try { initialize(); warmup(false); diff --git a/test/jdk/java/net/httpclient/http2/PostPutTest.java b/test/jdk/java/net/httpclient/http2/PostPutTest.java index 89b192f6171..84e86b556ca 100644 --- a/test/jdk/java/net/httpclient/http2/PostPutTest.java +++ b/test/jdk/java/net/httpclient/http2/PostPutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * does not process any data. The client should read all data from the server and close the connection. * @library /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer - * @run testng/othervm/timeout=50 -Djdk.httpclient.HttpClient.log=all + * @run junit/othervm/timeout=50 -Djdk.httpclient.HttpClient.log=all * PostPutTest */ @@ -36,11 +36,6 @@ import jdk.httpclient.test.lib.http2.Http2Handler; import jdk.httpclient.test.lib.http2.Http2TestExchange; import jdk.httpclient.test.lib.http2.Http2TestServer; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.IOException; import java.io.PrintStream; import java.net.URI; @@ -51,19 +46,24 @@ import java.net.http.HttpResponse; import static java.net.http.HttpClient.Version.HTTP_2; import static java.net.http.HttpRequest.BodyPublishers.ofByteArray; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PostPutTest { - Http2TestServer http2TestServer; - URI warmupURI, testHandlerBasicURI, testHandlerCloseBosURI, testHandleNegativeContentLengthURI; + private static Http2TestServer http2TestServer; + private static URI warmupURI, testHandlerBasicURI, testHandlerCloseBosURI, testHandleNegativeContentLengthURI; static PrintStream testLog = System.err; // As per jdk.internal.net.http.WindowController.DEFAULT_INITIAL_WINDOW_SIZE - final int DEFAULT_INITIAL_WINDOW_SIZE = (64 * 1024) - 1; + private static final int DEFAULT_INITIAL_WINDOW_SIZE = (64 * 1024) - 1; // Add on a small amount of arbitrary bytes to see if client hangs when receiving RST_STREAM - byte[] data = new byte[DEFAULT_INITIAL_WINDOW_SIZE + 10]; + private static byte[] data = new byte[DEFAULT_INITIAL_WINDOW_SIZE + 10]; - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { http2TestServer = new Http2TestServer(false, 0); http2TestServer.addHandler(new WarmupHandler(), "/Warmup"); http2TestServer.addHandler(new TestHandlerBasic(), "/TestHandlerBasic"); @@ -81,15 +81,14 @@ public class PostPutTest { testLog.println("PostPutTest.setup(): testHandleNegativeContentLengthURI: " + testHandleNegativeContentLengthURI); } - @AfterTest - public void teardown() { + @AfterAll + public static void teardown() { testLog.println("PostPutTest.teardown(): Stopping server"); http2TestServer.stop(); data = null; } - @DataProvider(name = "variants") - public Object[][] variants() { + public static Object[][] variants() { HttpRequest over64kPost, over64kPut, over64kPostCloseBos, over64kPutCloseBos, over64kPostNegativeContentLength, over64kPutNegativeContentLength; over64kPost = HttpRequest.newBuilder().version(HTTP_2).POST(ofByteArray(data)).uri(testHandlerBasicURI).build(); over64kPut = HttpRequest.newBuilder().version(HTTP_2).PUT(ofByteArray(data)).uri(testHandlerBasicURI).build(); @@ -117,7 +116,8 @@ public class PostPutTest { .build(); } - @Test(dataProvider = "variants") + @ParameterizedTest + @MethodSource("variants") public void testOver64kPUT(HttpRequest req, String testMessage) { testLog.println("PostPutTest: Performing test: " + testMessage); HttpClient hc = HttpClient.newBuilder().version(HTTP_2).build(); diff --git a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java index e9c6447e600..2d5b5dd4f4e 100644 --- a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java +++ b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,10 +31,9 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer * jdk.httpclient.test.lib.http2.BodyOutputStream * jdk.httpclient.test.lib.http2.OutgoingPushPromise - * @run testng/othervm PushPromiseContinuation + * @run junit/othervm PushPromiseContinuation */ - import javax.net.ssl.SSLSession; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -68,14 +67,13 @@ import jdk.internal.net.http.common.HttpHeadersBuilder; import jdk.internal.net.http.frame.ContinuationFrame; import jdk.internal.net.http.frame.HeaderFrame; -import org.testng.TestException; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; - import static java.nio.charset.StandardCharsets.UTF_8; -import static org.testng.Assert.*; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; public class PushPromiseContinuation { @@ -85,8 +83,8 @@ public class PushPromiseContinuation { static volatile int continuationCount; static final String mainPromiseBody = "Main Promise Body"; static final String mainResponseBody = "Main Response Body"; - Http2TestServer server; - URI uri; + private static Http2TestServer server; + private static URI uri; // Set up simple client-side push promise handler ConcurrentMap>> pushPromiseMap = new ConcurrentHashMap<>(); @@ -95,13 +93,13 @@ public class PushPromiseContinuation { pushPromiseMap.put(pushRequest, acceptor.apply(s)); }; - @BeforeMethod + @BeforeEach public void beforeMethod() { pushPromiseMap = new ConcurrentHashMap<>(); } - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { server = new Http2TestServer(false, 0); server.addHandler(new ServerPushHandler(), "/"); @@ -115,9 +113,8 @@ public class PushPromiseContinuation { uri = new URI("http://localhost:" + port + "/"); } - @AfterTest - public void teardown() { - pushPromiseMap = null; + @AfterAll + public static void teardown() { server.stop(); } @@ -195,29 +192,29 @@ public class PushPromiseContinuation { CompletableFuture> cf = client.sendAsync(hreq, HttpResponse.BodyHandlers.ofString(UTF_8), pph); - CompletionException t = expectThrows(CompletionException.class, () -> cf.join()); - assertEquals(t.getCause().getClass(), ProtocolException.class, + CompletionException t = assertThrows(CompletionException.class, () -> cf.join()); + assertEquals(ProtocolException.class, t.getCause().getClass(), "Expected a ProtocolException but got " + t.getCause()); System.err.println("Client received the following expected exception: " + t.getCause()); faultyServer.stop(); } private void verify(HttpResponse resp) { - assertEquals(resp.statusCode(), 200); - assertEquals(resp.body(), mainResponseBody); + assertEquals(200, resp.statusCode()); + assertEquals(mainResponseBody, resp.body()); if (pushPromiseMap.size() > 1) { System.err.println(pushPromiseMap.entrySet()); - throw new TestException("Results map size is greater than 1"); + fail("Results map size is greater than 1"); } else { // This will only iterate once for (HttpRequest r : pushPromiseMap.keySet()) { HttpResponse serverPushResp = pushPromiseMap.get(r).join(); // Received headers should be the same as the combined PushPromise // frame headers combined with the Continuation frame headers - assertEquals(testHeaders, r.headers()); + assertEquals(r.headers(), testHeaders); // Check status code and push promise body are as expected - assertEquals(serverPushResp.statusCode(), 200); - assertEquals(serverPushResp.body(), mainPromiseBody); + assertEquals(200, serverPushResp.statusCode()); + assertEquals(mainPromiseBody, serverPushResp.body()); } } } diff --git a/test/jdk/java/net/httpclient/http2/RedirectTest.java b/test/jdk/java/net/httpclient/http2/RedirectTest.java index e2acd807bd5..201b56513f6 100644 --- a/test/jdk/java/net/httpclient/http2/RedirectTest.java +++ b/test/jdk/java/net/httpclient/http2/RedirectTest.java @@ -30,7 +30,7 @@ * jdk.httpclient.test.lib.http2.Http2RedirectHandler * jdk.test.lib.Asserts * jdk.test.lib.net.SimpleSSLContext - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.HttpClient.log=frames,ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true * RedirectTest @@ -52,9 +52,10 @@ import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.httpclient.test.lib.http2.Http2TestExchange; import jdk.httpclient.test.lib.http2.Http2RedirectHandler; -import org.testng.annotations.Test; import static java.net.http.HttpClient.Version.HTTP_2; +import org.junit.jupiter.api.Test; + public class RedirectTest implements HttpServerAdapters { static int httpPort; static HttpTestServer httpServer; @@ -135,7 +136,7 @@ public class RedirectTest implements HttpServerAdapters { } @Test - public static void test() throws Exception { + public void test() throws Exception { try { initialize(); simpleTest(); diff --git a/test/jdk/java/net/httpclient/http2/ServerPush.java b/test/jdk/java/net/httpclient/http2/ServerPush.java index 7f9c82fb28b..d38b867132b 100644 --- a/test/jdk/java/net/httpclient/http2/ServerPush.java +++ b/test/jdk/java/net/httpclient/http2/ServerPush.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.httpclient.test.lib.http2.PushHandler * jdk.test.lib.Utils - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.HttpClient.log=errors,requests,responses * ServerPush */ @@ -48,13 +48,14 @@ import java.util.concurrent.*; import java.util.function.Consumer; import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.httpclient.test.lib.http2.PushHandler; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import static java.nio.charset.StandardCharsets.UTF_8; import static jdk.test.lib.Utils.createTempFileOfSize; -import static org.testng.Assert.*; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; public class ServerPush { @@ -66,11 +67,11 @@ public class ServerPush { static Path tempFile; - Http2TestServer server; - URI uri; + private static Http2TestServer server; + private static URI uri; - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { tempFile = createTempFileOfSize(TEMP_FILE_PREFIX, null, FILE_SIZE); server = new Http2TestServer(false, 0); server.addHandler(new PushHandler(tempFile, LOOPS), "/"); @@ -82,8 +83,8 @@ public class ServerPush { uri = new URI("http://localhost:" + port + "/foo/a/b/c"); } - @AfterTest - public void teardown() { + @AfterAll + public static void teardown() { server.stop(); } @@ -109,10 +110,10 @@ public class ServerPush { System.err.println("results.size: " + resultMap.size()); for (HttpRequest r : resultMap.keySet()) { HttpResponse response = resultMap.get(r).join(); - assertEquals(response.statusCode(), 200); - assertEquals(response.body(), tempFileAsString); + assertEquals(200, response.statusCode()); + assertEquals(tempFileAsString, response.body()); } - assertEquals(resultMap.size(), LOOPS + 1); + assertEquals(LOOPS + 1, resultMap.size()); } // Test 2 - of(...) populating the given Map, everything as a String @@ -135,10 +136,10 @@ public class ServerPush { System.err.println("results.size: " + resultMap.size()); for (HttpRequest r : resultMap.keySet()) { HttpResponse response = resultMap.get(r).join(); - assertEquals(response.statusCode(), 200); - assertEquals(response.body(), tempFileAsString); + assertEquals(200, response.statusCode()); + assertEquals(tempFileAsString, response.body()); } - assertEquals(resultMap.size(), LOOPS + 1); + assertEquals(LOOPS + 1, resultMap.size()); } // --- Path --- @@ -177,11 +178,11 @@ public class ServerPush { for (HttpRequest r : resultsMap.keySet()) { HttpResponse response = resultsMap.get(r).join(); - assertEquals(response.statusCode(), 200); + assertEquals(200, response.statusCode()); String fileAsString = new String(Files.readAllBytes(response.body()), UTF_8); - assertEquals(fileAsString, tempFileAsString); + assertEquals(tempFileAsString, fileAsString); } - assertEquals(resultsMap.size(), LOOPS + 1); + assertEquals(LOOPS + 1, resultsMap.size()); } // Test 4 - of(...) populating the given Map, everything as a Path @@ -204,11 +205,11 @@ public class ServerPush { for (HttpRequest r : resultsMap.keySet()) { HttpResponse response = resultsMap.get(r).join(); - assertEquals(response.statusCode(), 200); + assertEquals(200, response.statusCode()); String fileAsString = new String(Files.readAllBytes(response.body()), UTF_8); - assertEquals(fileAsString, tempFileAsString); + assertEquals(tempFileAsString, fileAsString); } - assertEquals(resultsMap.size(), LOOPS + 1); + assertEquals(LOOPS + 1, resultsMap.size()); } // --- Consumer --- @@ -263,12 +264,12 @@ public class ServerPush { for (HttpRequest r : resultsMap.keySet()) { HttpResponse response = resultsMap.get(r).join(); - assertEquals(response.statusCode(), 200); + assertEquals(200, response.statusCode()); byte[] ba = byteArrayConsumerMap.get(r).getAccumulatedBytes(); String result = new String(ba, UTF_8); - assertEquals(result, tempFileAsString); + assertEquals(tempFileAsString, result); } - assertEquals(resultsMap.size(), LOOPS + 1); + assertEquals(LOOPS + 1, resultsMap.size()); } // Test 6 - of(...) populating the given Map, everything as a consumer of optional byte[] @@ -301,11 +302,11 @@ public class ServerPush { for (HttpRequest r : resultsMap.keySet()) { HttpResponse response = resultsMap.get(r).join(); - assertEquals(response.statusCode(), 200); + assertEquals(200, response.statusCode()); byte[] ba = byteArrayConsumerMap.get(r).getAccumulatedBytes(); String result = new String(ba, UTF_8); - assertEquals(result, tempFileAsString); + assertEquals(tempFileAsString, result); } - assertEquals(resultsMap.size(), LOOPS + 1); + assertEquals(LOOPS + 1, resultsMap.size()); } } diff --git a/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java b/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java index 3e12a20c15e..9cf2a3f7ae2 100644 --- a/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java +++ b/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses * ServerPushWithDiffTypes @@ -47,9 +47,10 @@ import jdk.httpclient.test.lib.http2.Http2TestServer; import jdk.httpclient.test.lib.http2.Http2TestExchange; import jdk.httpclient.test.lib.http2.Http2Handler; -import org.testng.annotations.Test; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.testng.Assert.assertEquals; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ServerPushWithDiffTypes { @@ -66,7 +67,7 @@ public class ServerPushWithDiffTypes { ); @Test - public static void test() throws Exception { + public void test() throws Exception { Http2TestServer server = null; try { server = new Http2TestServer(false, 0); @@ -93,7 +94,7 @@ public class ServerPushWithDiffTypes { results.put(request, cf); cf.join(); - assertEquals(results.size(), PUSH_PROMISES.size() + 1); + assertEquals(PUSH_PROMISES.size() + 1, results.size()); for (HttpRequest r : results.keySet()) { URI u = r.uri(); @@ -116,7 +117,7 @@ public class ServerPushWithDiffTypes { String expected = PUSH_PROMISES.get(r.uri().getPath()); if (expected == null) expected = "the main response body"; - assertEquals(result, expected); + assertEquals(expected, result); } } finally { server.stop(); diff --git a/test/jdk/java/net/httpclient/http2/SimpleGet.java b/test/jdk/java/net/httpclient/http2/SimpleGet.java index 692a6583b63..5df3174f820 100644 --- a/test/jdk/java/net/httpclient/http2/SimpleGet.java +++ b/test/jdk/java/net/httpclient/http2/SimpleGet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,11 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.http2.Http2TestServer - * @run testng/othervm -XX:+CrashOnOutOfMemoryError SimpleGet - * @run testng/othervm -XX:+CrashOnOutOfMemoryError + * @run junit/othervm -XX:+CrashOnOutOfMemoryError SimpleGet + * @run junit/othervm -XX:+CrashOnOutOfMemoryError * -Dsimpleget.repeat=1 -Dsimpleget.chunks=1 -Dsimpleget.requests=1000 * SimpleGet - * @run testng/othervm -Dsimpleget.requests=150 + * @run junit/othervm -Dsimpleget.requests=150 * -Dsimpleget.chunks=16384 * -Djdk.httpclient.redirects.retrylimit=5 * -Djdk.httpclient.HttpClient.log=errors @@ -62,11 +62,12 @@ import javax.net.ssl.SSLContext; import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.test.lib.net.SimpleSSLContext; -import org.testng.Assert; -import org.testng.annotations.Test; import static java.net.http.HttpClient.Version.HTTP_2; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class SimpleGet implements HttpServerAdapters { static HttpTestServer httpsServer; static HttpClient client = null; @@ -117,11 +118,11 @@ public class SimpleGet implements HttpServerAdapters { } public static void main(String[] args) throws Exception { - test(); + new SimpleGet().test(); } @Test - public static void test() throws Exception { + public void test() throws Exception { try { long prestart = System.nanoTime(); initialize(); @@ -132,7 +133,7 @@ public class SimpleGet implements HttpServerAdapters { .GET().build(); long start = System.nanoTime(); var resp = client.send(request, BodyHandlers.ofByteArrayConsumer(b -> {})); - Assert.assertEquals(resp.statusCode(), 200); + assertEquals(200, resp.statusCode()); long elapsed = System.nanoTime() - start; System.out.println("Stat: First request took: " + elapsed + " nanos (" + TimeUnit.NANOSECONDS.toMillis(elapsed) + " ms)"); final int max = property("simpleget.requests", 50); @@ -163,7 +164,7 @@ public class SimpleGet implements HttpServerAdapters { + connections.size() + " connections"); } } - list.forEach((cf) -> Assert.assertEquals(cf.join().statusCode(), 200)); + list.forEach((cf) -> assertEquals(200, cf.join().statusCode())); } catch (Throwable tt) { System.err.println("tt caught"); tt.printStackTrace(); diff --git a/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java index 3edf0b71305..a36fe29813c 100644 --- a/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java +++ b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @bug 8342075 8343855 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext - * @run testng/othervm -Djdk.internal.httpclient.debug=true + * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.connectionWindowSize=65535 * -Djdk.httpclient.windowsize=16384 * StreamFlowControlTest @@ -65,30 +65,30 @@ import jdk.internal.net.http.common.HttpHeadersBuilder; import jdk.internal.net.http.frame.SettingsFrame; import jdk.test.lib.Utils; import jdk.test.lib.net.SimpleSSLContext; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.util.concurrent.TimeUnit.NANOSECONDS; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class StreamFlowControlTest { private static final SSLContext sslContext = SimpleSSLContext.findSSLContext(); - HttpTestServer http2TestServer; // HTTP/2 ( h2c ) - HttpTestServer https2TestServer; // HTTP/2 ( h2 ) - String http2URI; - String https2URI; - final AtomicInteger reqid = new AtomicInteger(); + private static HttpTestServer http2TestServer; // HTTP/2 ( h2c ) + private static HttpTestServer https2TestServer; // HTTP/2 ( h2 ) + private static String http2URI; + private static String https2URI; + private static final AtomicInteger reqid = new AtomicInteger(); final static int WINDOW = Integer.getInteger("jdk.httpclient.windowsize", 2 * 16 * 1024); - @DataProvider(name = "variants") - public Object[][] variants() { + public static Object[][] variants() { return new Object[][] { { http2URI, false }, { https2URI, false }, @@ -111,7 +111,8 @@ public class StreamFlowControlTest { } - @Test(dataProvider = "variants") + @ParameterizedTest + @MethodSource("variants") void test(String uri, boolean sameClient) throws Exception @@ -142,7 +143,7 @@ public class StreamFlowControlTest { if (sameClient) { String key = response.headers().firstValue("X-Connection-Key").get(); if (label == null) label = key; - assertEquals(key, label, "Unexpected key for " + query); + assertEquals(label, key, "Unexpected key for " + query); } sent.join(); // we have to pull to get the exception, but slow enough @@ -175,7 +176,8 @@ public class StreamFlowControlTest { } - @Test(dataProvider = "variants") + @ParameterizedTest + @MethodSource("variants") void testAsync(String uri, boolean sameClient) { @@ -207,7 +209,7 @@ public class StreamFlowControlTest { if (sameClient) { String key = response.headers().firstValue("X-Connection-Key").get(); if (label == null) label = key; - assertEquals(key, label, "Unexpected key for " + query); + assertEquals(label, key, "Unexpected key for " + query); } sent.join(); long wait = uri.startsWith("https://") ? 800 : 350; @@ -264,38 +266,38 @@ public class StreamFlowControlTest { } } - @BeforeTest - public void setup() throws Exception { - var http2TestServer = new Http2TestServer("localhost", false, 0); - http2TestServer.addHandler(new Http2TestHandler(), "/http2/"); - this.http2TestServer = HttpTestServer.of(http2TestServer); - http2URI = "http://" + this.http2TestServer.serverAuthority() + "/http2/x"; + @BeforeAll + public static void setup() throws Exception { + var http2TestServerImpl = new Http2TestServer("localhost", false, 0); + http2TestServerImpl.addHandler(new Http2TestHandler(), "/http2/"); + http2TestServer = HttpTestServer.of(http2TestServerImpl); + http2URI = "http://" + http2TestServer.serverAuthority() + "/http2/x"; - var https2TestServer = new Http2TestServer("localhost", true, sslContext); - https2TestServer.addHandler(new Http2TestHandler(), "/https2/"); - this.https2TestServer = HttpTestServer.of(https2TestServer); - this.https2TestServer.addHandler(new HttpHeadOrGetHandler(), "/https2/head/"); - https2URI = "https://" + this.https2TestServer.serverAuthority() + "/https2/x"; - String h2Head = "https://" + this.https2TestServer.serverAuthority() + "/https2/head/z"; + var https2TestServerImpl = new Http2TestServer("localhost", true, sslContext); + https2TestServerImpl.addHandler(new Http2TestHandler(), "/https2/"); + https2TestServer = HttpTestServer.of(https2TestServerImpl); + https2TestServer.addHandler(new HttpHeadOrGetHandler(), "/https2/head/"); + https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/x"; + String h2Head = "https://" + https2TestServer.serverAuthority() + "/https2/head/z"; // Override the default exchange supplier with a custom one to enable // particular test scenarios - http2TestServer.setExchangeSupplier(FCHttp2TestExchange::new); - https2TestServer.setExchangeSupplier(FCHttp2TestExchange::new); + http2TestServerImpl.setExchangeSupplier(FCHttp2TestExchange::new); + https2TestServerImpl.setExchangeSupplier(FCHttp2TestExchange::new); - this.http2TestServer.start(); - this.https2TestServer.start(); + http2TestServer.start(); + https2TestServer.start(); // warmup to eliminate delay due to SSL class loading and initialization. try (var client = HttpClient.newBuilder().sslContext(sslContext).build()) { var request = HttpRequest.newBuilder(URI.create(h2Head)).HEAD().build(); var resp = client.send(request, BodyHandlers.discarding()); - assertEquals(resp.statusCode(), 200); + assertEquals(200, resp.statusCode()); } } - @AfterTest - public void teardown() throws Exception { + @AfterAll + public static void teardown() throws Exception { http2TestServer.stop(); https2TestServer.stop(); } diff --git a/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java b/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java index 9fa6f8b728e..9ea331d2d84 100644 --- a/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java +++ b/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @bug 8296410 * @library /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer - * @run testng/othervm -Djdk.httpclient.HttpClient.log=all TrailingHeadersTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=all TrailingHeadersTest */ import jdk.httpclient.test.lib.http2.OutgoingPushPromise; @@ -36,11 +36,6 @@ import jdk.internal.net.http.common.HttpHeadersBuilder; import jdk.internal.net.http.frame.DataFrame; import jdk.internal.net.http.frame.HeaderFrame; import jdk.internal.net.http.frame.HeadersFrame; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import javax.net.ssl.SSLSession; import java.io.ByteArrayInputStream; @@ -74,24 +69,30 @@ import jdk.httpclient.test.lib.http2.BodyOutputStream; import static java.net.http.HttpClient.Version.HTTP_2; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.testng.Assert.assertEquals; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TrailingHeadersTest { - Http2TestServer http2TestServer; - URI trailingURI, trailng1xxURI, trailingPushPromiseURI, warmupURI; + private static Http2TestServer http2TestServer; + private static URI trailingURI, trailng1xxURI, trailingPushPromiseURI, warmupURI; static PrintStream testLog = System.err; // Set up simple client-side push promise handler - ConcurrentMap>> pushPromiseMap = new ConcurrentHashMap<>(); + private static ConcurrentMap>> pushPromiseMap = new ConcurrentHashMap<>(); - @BeforeMethod + @BeforeEach public void beforeMethod() { pushPromiseMap = new ConcurrentHashMap<>(); } - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { Properties props = new Properties(); // For triggering trailing headers to send after Push Promise Response headers are sent props.setProperty("sendTrailingHeadersAfterPushPromise", "1"); @@ -119,12 +120,13 @@ public class TrailingHeadersTest { warmupURI = URI.create("http://" + http2TestServer.serverAuthority() + "/WarmupHandler"); } - @AfterTest - public void teardown() { + @AfterAll + public static void teardown() { http2TestServer.stop(); } - @Test(dataProvider = "httpRequests") + @ParameterizedTest + @MethodSource("uris") public void testTrailingHeaders(String description, HttpRequest hRequest, HttpResponse.PushPromiseHandler pph) { testLog.println("testTrailingHeaders(): " + description); HttpClient httpClient = HttpClient.newBuilder().build(); @@ -134,7 +136,7 @@ public class TrailingHeadersTest { testLog.println("testTrailingHeaders(): Performing request: " + hRequest); HttpResponse resp = cf.join(); - assertEquals(resp.statusCode(), 200, "Status code of response should be 200"); + assertEquals(200, resp.statusCode(), "Status code of response should be 200"); // Verify Push Promise was successful if necessary if (pph != null) @@ -144,14 +146,14 @@ public class TrailingHeadersTest { } private void verifyPushPromise() { - assertEquals(pushPromiseMap.size(), 1, "Push Promise should not be greater than 1"); + assertEquals(1, pushPromiseMap.size(), "Push Promise should not be greater than 1"); // This will only iterate once for (HttpRequest r : pushPromiseMap.keySet()) { CompletableFuture> serverPushResp = pushPromiseMap.get(r); // Get the push promise HttpResponse result if present HttpResponse resp = serverPushResp.join(); - assertEquals(resp.body(), "Sample_Push_Data", "Unexpected Push Promise response body"); - assertEquals(resp.statusCode(), 200, "Status code of Push Promise response should be 200"); + assertEquals("Sample_Push_Data", resp.body(), "Unexpected Push Promise response body"); + assertEquals(200, resp.statusCode(), "Status code of Push Promise response should be 200"); } } @@ -162,11 +164,10 @@ public class TrailingHeadersTest { httpClient.sendAsync(warmupReq, BodyHandlers.discarding()).join(); } - @DataProvider(name = "httpRequests") - public Object[][] uris() { + public static Object[][] uris() { HttpResponse.PushPromiseHandler pph = (initial, pushRequest, acceptor) -> { HttpResponse.BodyHandler s = HttpResponse.BodyHandlers.ofString(UTF_8); - pushPromiseMap.put(pushRequest, acceptor.apply(s)); + TrailingHeadersTest.pushPromiseMap.put(pushRequest, acceptor.apply(s)); }; HttpRequest httpGetTrailing = HttpRequest.newBuilder(trailingURI).version(HTTP_2) diff --git a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HeaderTableTest.java b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HeaderTableTest.java index 0eb1714da35..07e27a7f2fa 100644 --- a/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HeaderTableTest.java +++ b/test/jdk/java/net/httpclient/http2/java.net.http/jdk/internal/net/http/hpack/HeaderTableTest.java @@ -29,9 +29,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.junit.jupiter.api.Assertions; -import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; public class HeaderTableTest extends SimpleHeaderTableTest { @@ -76,7 +76,7 @@ public class HeaderTableTest extends SimpleHeaderTableTest { Set expectedIndexes = indexes.get(hName); int actualMinimalIndex = table.indexOf(hName, "blah-blah"); - Assertions.assertTrue(expectedIndexes.contains(-actualMinimalIndex)); + assertTrue(expectedIndexes.contains(-actualMinimalIndex)); }); } From dfea6eb9f84142aaa3e51181ea345e8575729ea2 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 5 Mar 2026 11:13:15 +0000 Subject: [PATCH 054/655] 8378598: Refactor tests under test/jdk/java/net/httpclient/websocket from TestNG to JUnit Reviewed-by: vyazici --- .../java/net/httpclient/websocket/Abort.java | 31 ++++---- .../httpclient/websocket/AutomaticPong.java | 32 +++++---- .../websocket/BlowupOutputQueue.java | 9 ++- .../websocket/HandshakeUrlEncodingTest.java | 50 ++++++------- .../websocket/HeaderWriterDriver.java | 4 +- .../httpclient/websocket/MaskerDriver.java | 4 +- .../websocket/MessageQueueDriver.java | 4 +- .../websocket/PendingBinaryPingClose.java | 12 ++-- .../websocket/PendingBinaryPongClose.java | 12 ++-- .../websocket/PendingOperations.java | 12 ++-- .../websocket/PendingPingBinaryClose.java | 12 ++-- .../websocket/PendingPingTextClose.java | 12 ++-- .../websocket/PendingPongBinaryClose.java | 12 ++-- .../websocket/PendingPongTextClose.java | 12 ++-- .../websocket/PendingTextPingClose.java | 12 ++-- .../websocket/PendingTextPongClose.java | 12 ++-- .../httpclient/websocket/ReaderDriver.java | 6 +- .../httpclient/websocket/SecureSupport.java | 11 +-- .../net/httpclient/websocket/SendTest.java | 16 ++--- .../net/httpclient/websocket/Support.java | 6 +- .../websocket/WSHandshakeExceptionTest.java | 55 +++++++-------- .../websocket/WebSocketBuilderTest.java | 32 ++++----- .../websocket/WebSocketExtendedTest.java | 70 ++++++++++--------- .../websocket/WebSocketProxyTest.java | 28 ++++---- .../httpclient/websocket/WebSocketTest.java | 42 ++++++----- .../net/http/websocket/HeaderWriterTest.java | 9 +-- .../net/http/websocket/MaskerTest.java | 20 +++--- .../net/http/websocket/MessageQueueTest.java | 44 ++++++------ .../net/http/websocket/ReaderTest.java | 25 +++---- .../websocket/security/WSSanityTest.java | 37 +++++----- 30 files changed, 333 insertions(+), 310 deletions(-) diff --git a/test/jdk/java/net/httpclient/websocket/Abort.java b/test/jdk/java/net/httpclient/websocket/Abort.java index 99c94de83f0..a6088f8cce2 100644 --- a/test/jdk/java/net/httpclient/websocket/Abort.java +++ b/test/jdk/java/net/httpclient/websocket/Abort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,11 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.websocket.debug=true * Abort */ -import org.testng.annotations.Test; import java.io.IOException; import java.net.ProtocolException; @@ -44,10 +43,12 @@ import java.util.concurrent.TimeoutException; import static java.net.http.HttpClient.newHttpClient; import static java.net.http.WebSocket.NORMAL_CLOSURE; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.Test; public class Abort { @@ -79,7 +80,7 @@ public class Abort { TimeUnit.SECONDS.sleep(5); List inv = listener.invocationsSoFar(); // no more invocations after onOpen as WebSocket was aborted - assertEquals(inv, List.of(MockListener.Invocation.onOpen(webSocket))); + assertEquals(List.of(MockListener.Invocation.onOpen(webSocket)), inv); } finally { webSocket.abort(); } @@ -119,7 +120,7 @@ public class Abort { List expected = List.of( MockListener.Invocation.onOpen(webSocket), MockListener.Invocation.onText(webSocket, "", true)); - assertEquals(inv, expected); + assertEquals(expected, inv); } finally { webSocket.abort(); } @@ -159,7 +160,7 @@ public class Abort { List expected = List.of( MockListener.Invocation.onOpen(webSocket), MockListener.Invocation.onBinary(webSocket, ByteBuffer.allocate(0), true)); - assertEquals(inv, expected); + assertEquals(expected, inv); } finally { webSocket.abort(); } @@ -198,7 +199,7 @@ public class Abort { List expected = List.of( MockListener.Invocation.onOpen(webSocket), MockListener.Invocation.onPing(webSocket, ByteBuffer.allocate(0))); - assertEquals(inv, expected); + assertEquals(expected, inv); } finally { webSocket.abort(); } @@ -237,7 +238,7 @@ public class Abort { List expected = List.of( MockListener.Invocation.onOpen(webSocket), MockListener.Invocation.onPong(webSocket, ByteBuffer.allocate(0))); - assertEquals(inv, expected); + assertEquals(expected, inv); } finally { webSocket.abort(); } @@ -277,7 +278,7 @@ public class Abort { List expected = List.of( MockListener.Invocation.onOpen(webSocket), MockListener.Invocation.onClose(webSocket, 1005, "")); - assertEquals(inv, expected); + assertEquals(expected, inv); } finally { webSocket.abort(); } @@ -318,7 +319,7 @@ public class Abort { MockListener.Invocation.onOpen(webSocket), MockListener.Invocation.onError(webSocket, ProtocolException.class)); System.out.println("actual invocations:" + Arrays.toString(inv.toArray())); - assertEquals(inv, expected); + assertEquals(expected, inv); } finally { webSocket.abort(); } @@ -396,7 +397,7 @@ public class Abort { ws.abort(); assertTrue(ws.isInputClosed()); assertTrue(ws.isOutputClosed()); - assertEquals(ws.getSubprotocol(), ""); + assertEquals("", ws.getSubprotocol()); } // at this point valid requests MUST be a no-op: for (int j = 0; j < 3; j++) { diff --git a/test/jdk/java/net/httpclient/websocket/AutomaticPong.java b/test/jdk/java/net/httpclient/websocket/AutomaticPong.java index 1999781b82f..b438cb8e728 100644 --- a/test/jdk/java/net/httpclient/websocket/AutomaticPong.java +++ b/test/jdk/java/net/httpclient/websocket/AutomaticPong.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,11 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.websocket.debug=true * AutomaticPong */ import jdk.internal.net.http.websocket.Frame; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.http.WebSocket; @@ -39,10 +37,14 @@ import java.nio.charset.StandardCharsets; import java.util.List; import static java.net.http.HttpClient.newHttpClient; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class AutomaticPong { /* @@ -86,7 +88,7 @@ public class AutomaticPong { MockListener.Invocation.onPing(webSocket, hello), MockListener.Invocation.onClose(webSocket, 1005, "") ); - assertEquals(actual, expected); + assertEquals(expected, actual); } finally { webSocket.abort(); } @@ -104,7 +106,8 @@ public class AutomaticPong { * b) the last Pong corresponds to the last Ping * c) there are no unrelated Pongs */ - @Test(dataProvider = "nPings") + @ParameterizedTest + @MethodSource("nPings") public void automaticPongs(int nPings) throws Exception { // big enough to not bother with resize ByteBuffer buffer = ByteBuffer.allocate(65536); @@ -133,7 +136,7 @@ public class AutomaticPong { .join(); try { List inv = listener.invocations(); - assertEquals(inv.size(), nPings + 2); // n * onPing + onOpen + onClose + assertEquals(nPings + 2, inv.size()); // n * onPing + onOpen + onClose ByteBuffer data = server.read(); Frame.Reader reader = new Frame.Reader(); @@ -171,7 +174,7 @@ public class AutomaticPong { closed = true; return; } - assertEquals(value, Frame.Opcode.PONG); + assertEquals(Frame.Opcode.PONG, value); } @Override @@ -182,7 +185,7 @@ public class AutomaticPong { @Override public void payloadLen(long value) { if (!closed) - assertEquals(value, 4); + assertEquals(4, value); } @Override @@ -222,8 +225,7 @@ public class AutomaticPong { } - @DataProvider(name = "nPings") - public Object[][] nPings() { + public static Object[][] nPings() { return new Object[][]{{1}, {2}, {4}, {8}, {9}, {256}}; } } diff --git a/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java b/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java index 7bf2564a04f..1865ca05e4f 100644 --- a/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java +++ b/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,14 +24,12 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * BlowupOutputQueue */ -import org.testng.annotations.Test; - import java.io.IOException; import java.net.http.WebSocket; import java.nio.ByteBuffer; @@ -43,7 +41,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.testng.Assert.assertFalse; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; public class BlowupOutputQueue extends PendingOperations { diff --git a/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java b/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java index 25a6893ff13..6854cacbcc2 100644 --- a/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java +++ b/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestServerConfigurator * @modules java.net.http/jdk.internal.net.http.common * jdk.httpserver - * @run testng/othervm -Djdk.internal.httpclient.debug=true HandshakeUrlEncodingTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true HandshakeUrlEncodingTest */ import com.sun.net.httpserver.HttpHandler; @@ -39,10 +39,6 @@ import com.sun.net.httpserver.HttpExchange; import jdk.httpclient.test.lib.common.TestServerConfigurator; import jdk.test.lib.net.SimpleSSLContext; import jdk.test.lib.net.URIBuilder; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import java.io.IOException; @@ -58,20 +54,25 @@ import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - import static java.net.http.HttpClient.Builder.NO_PROXY; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.fail; import static java.lang.System.out; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + + public class HandshakeUrlEncodingTest { private static final SSLContext sslContext = SimpleSSLContext.findSSLContext(); - HttpServer httpTestServer; - HttpsServer httpsTestServer; - String httpURI; - String httpsURI; + private static HttpServer httpTestServer; + private static HttpsServer httpsTestServer; + private static String httpURI; + private static String httpsURI; static String queryPart; @@ -79,8 +80,7 @@ public class HandshakeUrlEncodingTest { // a shared executor helps reduce the amount of threads created by the test static final ExecutorService executor = Executors.newCachedThreadPool(); - @DataProvider(name = "variants") - public Object[][] variants() { + public static Object[][] variants() { return new Object[][]{ { httpURI, false }, { httpsURI, false }, @@ -97,7 +97,8 @@ public class HandshakeUrlEncodingTest { .build(); } - @Test(dataProvider = "variants") + @ParameterizedTest + @MethodSource("variants") public void test(String uri, boolean sameClient) { HttpClient client = null; out.println("The url is " + uri); @@ -119,22 +120,21 @@ public class HandshakeUrlEncodingTest { final WebSocketHandshakeException wse = (WebSocketHandshakeException) t; assertNotNull(wse.getResponse()); assertNotNull(wse.getResponse().uri()); - assertNotNull(wse.getResponse().statusCode()); final String rawQuery = wse.getResponse().uri().getRawQuery(); final String expectedRawQuery = "&raw=abc+def/ghi=xyz&encoded=abc%2Bdef%2Fghi%3Dxyz"; - assertEquals(rawQuery, expectedRawQuery); + assertEquals(expectedRawQuery, rawQuery); final String body = (String) wse.getResponse().body(); final String expectedBody = "/?" + expectedRawQuery; - assertEquals(body, expectedBody); + assertEquals(expectedBody, body); out.println("Status code is " + wse.getResponse().statusCode()); out.println("Response is " + wse.getResponse()); - assertEquals(wse.getResponse().statusCode(), 400); + assertEquals(400, wse.getResponse().statusCode()); } } } - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); queryPart = "?&raw=abc+def/ghi=xyz&encoded=abc%2Bdef%2Fghi%3Dxyz"; httpTestServer = HttpServer.create(sa, 10); @@ -164,8 +164,8 @@ public class HandshakeUrlEncodingTest { httpsTestServer.start(); } - @AfterTest - public void teardown() { + @AfterAll + public static void teardown() { httpTestServer.stop(0); httpsTestServer.stop(0); executor.shutdownNow(); diff --git a/test/jdk/java/net/httpclient/websocket/HeaderWriterDriver.java b/test/jdk/java/net/httpclient/websocket/HeaderWriterDriver.java index 6293b1b6c71..75ae5423f00 100644 --- a/test/jdk/java/net/httpclient/websocket/HeaderWriterDriver.java +++ b/test/jdk/java/net/httpclient/websocket/HeaderWriterDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8159053 * @modules java.net.http/jdk.internal.net.http.websocket:open - * @run testng/othervm + * @run junit/othervm * --add-reads java.net.http=ALL-UNNAMED * java.net.http/jdk.internal.net.http.websocket.HeaderWriterTest */ diff --git a/test/jdk/java/net/httpclient/websocket/MaskerDriver.java b/test/jdk/java/net/httpclient/websocket/MaskerDriver.java index b84ea1fff5c..e81417c25ef 100644 --- a/test/jdk/java/net/httpclient/websocket/MaskerDriver.java +++ b/test/jdk/java/net/httpclient/websocket/MaskerDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8159053 * @modules java.net.http/jdk.internal.net.http.websocket:open - * @run testng/othervm + * @run junit/othervm * --add-reads java.net.http=ALL-UNNAMED * java.net.http/jdk.internal.net.http.websocket.MaskerTest */ diff --git a/test/jdk/java/net/httpclient/websocket/MessageQueueDriver.java b/test/jdk/java/net/httpclient/websocket/MessageQueueDriver.java index 9831bb59297..68a23d0be88 100644 --- a/test/jdk/java/net/httpclient/websocket/MessageQueueDriver.java +++ b/test/jdk/java/net/httpclient/websocket/MessageQueueDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8159053 * @modules java.net.http/jdk.internal.net.http.websocket:open - * @run testng/othervm + * @run junit/othervm * --add-reads java.net.http=ALL-UNNAMED * java.net.http/jdk.internal.net.http.websocket.MessageQueueTest */ diff --git a/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java b/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java index 5a410251593..4a5ae315e91 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,28 +24,30 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * PendingBinaryPingClose */ -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingBinaryPingClose extends PendingOperations { CompletableFuture cfBinary; CompletableFuture cfPing; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingBinaryPingClose(boolean last) throws Exception { repeatable(() -> { server = Support.notReadingServer(); diff --git a/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java b/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java index bef3d258850..a8330faeb3f 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,28 +24,30 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * PendingBinaryPongClose */ -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingBinaryPongClose extends PendingOperations { CompletableFuture cfBinary; CompletableFuture cfPong; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingBinaryPongClose(boolean last) throws Exception { repeatable(() -> { server = Support.notReadingServer(); diff --git a/test/jdk/java/net/httpclient/websocket/PendingOperations.java b/test/jdk/java/net/httpclient/websocket/PendingOperations.java index b4d7d7e2222..32350a1ab41 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingOperations.java +++ b/test/jdk/java/net/httpclient/websocket/PendingOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,9 +21,6 @@ * questions. */ -import org.testng.annotations.AfterMethod; -import org.testng.annotations.DataProvider; - import java.io.IOException; import java.net.http.HttpClient; import java.net.http.WebSocket; @@ -35,6 +32,8 @@ import java.util.function.BooleanSupplier; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.newBuilder; +import org.junit.jupiter.api.AfterEach; + /* Common infrastructure for tests that check pending operations */ public class PendingOperations { @@ -54,7 +53,7 @@ public class PendingOperations { return newBuilder().proxy(NO_PROXY).build(); } - @AfterMethod + @AfterEach public void cleanup() { // make sure we have a trace both on System.out and System.err // to help with diagnosis. @@ -85,8 +84,7 @@ public class PendingOperations { Support.assertNotDone(future); } - @DataProvider(name = "booleans") - public Object[][] booleans() { + public static Object[][] booleans() { return new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}}; } diff --git a/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java b/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java index c1c314395e8..e07ebe0d03a 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 * PendingPingBinaryClose */ @@ -33,21 +33,23 @@ // * -Djdk.internal.httpclient.debug=true // * -Djdk.internal.httpclient.websocket.debug=true -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingPingBinaryClose extends PendingOperations { CompletableFuture cfBinary; CompletableFuture cfPing; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingPingBinaryClose(boolean last) throws Exception { repeatable( () -> { server = Support.notReadingServer(); diff --git a/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java b/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java index 82666fafe67..eae01f804a4 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 * PendingPingTextClose */ @@ -33,14 +33,15 @@ // * -Djdk.internal.httpclient.debug=true // * -Djdk.internal.httpclient.websocket.debug=true -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingPingTextClose extends PendingOperations { static boolean debug = false; // avoid too verbose output @@ -48,7 +49,8 @@ public class PendingPingTextClose extends PendingOperations { CompletableFuture cfPing; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingPingTextClose(boolean last) throws Exception { try { repeatable(() -> { diff --git a/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java b/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java index 0aa2f24c660..32640853b00 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 * PendingPongBinaryClose */ @@ -33,21 +33,23 @@ // * -Djdk.internal.httpclient.debug=true // * -Djdk.internal.httpclient.websocket.debug=true -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingPongBinaryClose extends PendingOperations { CompletableFuture cfBinary; CompletableFuture cfPong; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingPongBinaryClose(boolean last) throws Exception { repeatable( () -> { server = Support.notReadingServer(); diff --git a/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java b/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java index f919a6706ad..f4d6c84c2f5 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 * PendingPongTextClose */ @@ -33,21 +33,23 @@ // * -Djdk.internal.httpclient.debug=true // * -Djdk.internal.httpclient.websocket.debug=true -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingPongTextClose extends PendingOperations { CompletableFuture cfText; CompletableFuture cfPong; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingPongTextClose(boolean last) throws Exception { repeatable( () -> { server = Support.notReadingServer(); diff --git a/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java b/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java index 39c8bbdc444..76f12430804 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,13 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.httpclient.sendBufferSize=8192 * PendingTextPingClose */ -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -40,13 +38,17 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingTextPingClose extends PendingOperations { CompletableFuture cfText; CompletableFuture cfPing; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingTextPingClose(boolean last) throws Exception { repeatable(() -> { server = Support.notReadingServer(); diff --git a/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java b/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java index 8fa90400760..a2a41a73d7b 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,13 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.httpclient.sendBufferSize=8192 * PendingTextPongClose */ -import org.testng.annotations.Test; - import java.net.http.WebSocket; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -40,13 +38,17 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + public class PendingTextPongClose extends PendingOperations { CompletableFuture cfText; CompletableFuture cfPong; CompletableFuture cfClose; - @Test(dataProvider = "booleans") + @ParameterizedTest + @MethodSource("booleans") public void pendingTextPongClose(boolean last) throws Exception { repeatable(() -> { server = Support.notReadingServer(); diff --git a/test/jdk/java/net/httpclient/websocket/ReaderDriver.java b/test/jdk/java/net/httpclient/websocket/ReaderDriver.java index 0b874792b4f..3e195be046d 100644 --- a/test/jdk/java/net/httpclient/websocket/ReaderDriver.java +++ b/test/jdk/java/net/httpclient/websocket/ReaderDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ * @test * @bug 8159053 * @modules java.net.http/jdk.internal.net.http.websocket:open - * @run testng/othervm/timeout=240 --add-reads java.net.http=ALL-UNNAMED java.net.http/jdk.internal.net.http.websocket.ReaderTest + * @run junit/othervm/timeout=240 + * --add-reads java.net.http=ALL-UNNAMED + * java.net.http/jdk.internal.net.http.websocket.ReaderTest */ public final class ReaderDriver { } diff --git a/test/jdk/java/net/httpclient/websocket/SecureSupport.java b/test/jdk/java/net/httpclient/websocket/SecureSupport.java index 8b565768c29..41709d2fedb 100644 --- a/test/jdk/java/net/httpclient/websocket/SecureSupport.java +++ b/test/jdk/java/net/httpclient/websocket/SecureSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,18 +22,9 @@ */ import java.io.IOException; -import java.net.Socket; import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import static org.testng.Assert.assertThrows; /** * Helper class to create instances of DummySecureWebSocketServer which diff --git a/test/jdk/java/net/httpclient/websocket/SendTest.java b/test/jdk/java/net/httpclient/websocket/SendTest.java index 39021131156..b3a433b5c29 100644 --- a/test/jdk/java/net/httpclient/websocket/SendTest.java +++ b/test/jdk/java/net/httpclient/websocket/SendTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,22 +24,22 @@ /* * @test * @build DummyWebSocketServer - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.websocket.debug=true * SendTest */ -import org.testng.annotations.Test; - import java.io.IOException; import java.net.http.WebSocket; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.newBuilder; import static java.net.http.WebSocket.NORMAL_CLOSURE; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SendTest { @@ -90,7 +90,7 @@ public class SendTest { try { webSocket.sendClose(NORMAL_CLOSURE, "").join(); assertTrue(webSocket.isOutputClosed()); - assertEquals(webSocket.getSubprotocol(), ""); + assertEquals("", webSocket.getSubprotocol()); webSocket.request(1); // No exceptions must be thrown } finally { webSocket.abort(); diff --git a/test/jdk/java/net/httpclient/websocket/Support.java b/test/jdk/java/net/httpclient/websocket/Support.java index 1323ae35105..73f840ff7eb 100644 --- a/test/jdk/java/net/httpclient/websocket/Support.java +++ b/test/jdk/java/net/httpclient/websocket/Support.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,8 @@ import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertFalse; public class Support { diff --git a/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java b/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java index 90db79dc8ef..f28d84b2f20 100644 --- a/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java +++ b/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestServerConfigurator * @modules java.net.http/jdk.internal.net.http.common * jdk.httpserver - * @run testng/othervm -Djdk.internal.httpclient.debug=true WSHandshakeExceptionTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true WSHandshakeExceptionTest */ import com.sun.net.httpserver.HttpHandler; @@ -37,8 +37,6 @@ import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpsServer; import com.sun.net.httpserver.HttpExchange; - - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -49,10 +47,6 @@ import java.net.http.WebSocketHandshakeException; import jdk.httpclient.test.lib.common.TestServerConfigurator; import jdk.test.lib.net.SimpleSSLContext; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import java.net.InetSocketAddress; import java.net.URI; @@ -62,29 +56,33 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static java.net.http.HttpClient.Builder.NO_PROXY; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; import static java.lang.System.out; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class WSHandshakeExceptionTest { private static final SSLContext sslContext = SimpleSSLContext.findSSLContext(); - HttpServer httpTestServer; // HTTP/1.1 [ 2 servers ] - HttpsServer httpsTestServer; // HTTPS/1.1 - String httpURI; - String httpsURI; - String httpNonUtf8URI; - String httpsNonUtf8URI; - HttpClient sharedClient; + private static HttpServer httpTestServer; // HTTP/1.1 [ 2 servers ] + private static HttpsServer httpsTestServer; // HTTPS/1.1 + private static String httpURI; + private static String httpsURI; + private static String httpNonUtf8URI; + private static String httpsNonUtf8URI; + private static HttpClient sharedClient; static final int ITERATION_COUNT = 4; // a shared executor helps reduce the amount of threads created by the test static final ExecutorService executor = Executors.newCachedThreadPool(); - @DataProvider(name = "variants") - public Object[][] variants() { + public static Object[][] variants() { return new Object[][]{ { httpURI, false }, { httpsURI, false }, @@ -106,7 +104,8 @@ public class WSHandshakeExceptionTest { .build(); } - @Test(dataProvider = "variants") + @ParameterizedTest + @MethodSource("variants") public void test(String uri, boolean sameClient) { HttpClient client = sharedClient; boolean pause; @@ -132,7 +131,7 @@ public class WSHandshakeExceptionTest { WebSocketHandshakeException wse = (WebSocketHandshakeException) t; assertNotNull(wse.getResponse()); assertNotNull(wse.getResponse().body()); - assertEquals(wse.getResponse().body().getClass(), String.class); + assertEquals(String.class, wse.getResponse().body().getClass()); String body = (String)wse.getResponse().body(); out.println("Status code is " + wse.getResponse().statusCode()); out.println("Response is " + body); @@ -145,7 +144,7 @@ public class WSHandshakeExceptionTest { // default HttpServer 404 body expected assertTrue(body.contains("404")); } - assertEquals(wse.getResponse().statusCode(), 404); + assertEquals(404, wse.getResponse().statusCode()); } } } @@ -159,8 +158,8 @@ public class WSHandshakeExceptionTest { } } - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { // HTTP/1.1 InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); httpTestServer = HttpServer.create(sa, 0); @@ -178,8 +177,8 @@ public class WSHandshakeExceptionTest { httpsTestServer.start(); } - @AfterTest - public void teardown() { + @AfterAll + public static void teardown() { sharedClient = null; gc(100); httpTestServer.stop(0); diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java index b28b8f59875..beef8cb42a4 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,9 @@ * @bug 8159053 * @build DummyWebSocketServer * Support - * @run testng/othervm WebSocketBuilderTest + * @run junit/othervm WebSocketBuilderTest */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.net.URI; import java.net.http.HttpClient; import java.net.http.WebSocket; @@ -42,7 +39,10 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.testng.Assert.assertThrows; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * In some places in this test a new String is created out of a string literal. @@ -98,7 +98,8 @@ public final class WebSocketBuilderTest { .connectTimeout(null)); } - @Test(dataProvider = "badURIs") + @ParameterizedTest + @MethodSource("badURIs") void illegalURI(URI uri) { WebSocket.Builder b = HttpClient.newHttpClient().newWebSocketBuilder(); assertFails(IllegalArgumentException.class, @@ -129,7 +130,8 @@ public final class WebSocketBuilderTest { // TODO: test for bad syntax headers // TODO: test for overwrites (subprotocols) and additions (headers) - @Test(dataProvider = "badSubprotocols") + @ParameterizedTest + @MethodSource("badSubprotocols") public void illegalSubprotocolsSyntax(String s) { WebSocket.Builder b = HttpClient.newHttpClient() .newWebSocketBuilder() @@ -138,7 +140,8 @@ public final class WebSocketBuilderTest { b.buildAsync(VALID_URI, listener())); } - @Test(dataProvider = "duplicatingSubprotocols") + @ParameterizedTest + @MethodSource("duplicatingSubprotocols") public void illegalSubprotocolsDuplicates(String mostPreferred, String[] lesserPreferred) { WebSocket.Builder b = HttpClient.newHttpClient() @@ -148,7 +151,8 @@ public final class WebSocketBuilderTest { b.buildAsync(VALID_URI, listener())); } - @Test(dataProvider = "badConnectTimeouts") + @ParameterizedTest + @MethodSource("badConnectTimeouts") public void illegalConnectTimeout(Duration d) { WebSocket.Builder b = HttpClient.newHttpClient() .newWebSocketBuilder() @@ -157,8 +161,7 @@ public final class WebSocketBuilderTest { b.buildAsync(VALID_URI, listener())); } - @DataProvider - public Object[][] badURIs() { + public static Object[][] badURIs() { return new Object[][]{ {URI.create("http://example.com")}, {URI.create("ftp://example.com")}, @@ -167,8 +170,7 @@ public final class WebSocketBuilderTest { }; } - @DataProvider - public Object[][] badConnectTimeouts() { + public static Object[][] badConnectTimeouts() { return new Object[][]{ {Duration.ofDays(0)}, {Duration.ofDays(-1)}, @@ -188,7 +190,6 @@ public final class WebSocketBuilderTest { // https://tools.ietf.org/html/rfc7230#section-3.2.6 // https://tools.ietf.org/html/rfc20 - @DataProvider public static Object[][] badSubprotocols() { return new Object[][]{ {""}, @@ -215,7 +216,6 @@ public final class WebSocketBuilderTest { }; } - @DataProvider public static Object[][] duplicatingSubprotocols() { return new Object[][]{ {"a.b.c", new String[]{"a.b.c"}}, diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java index 0099104e872..56474555235 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 8159053 - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.websocket.writeBufferSize=1024 @@ -32,8 +32,6 @@ */ import jdk.internal.net.http.websocket.Frame; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.http.WebSocket; @@ -43,8 +41,11 @@ import java.util.List; import java.util.Random; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.newBuilder; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /* @@ -52,7 +53,7 @@ import static org.testng.Assert.assertTrue; * possible fragmentation. */ public class WebSocketExtendedTest { -// * run testng/othervm +// * run junit/othervm // * -Djdk.httpclient.websocket.writeBufferSize=16 // * -Djdk.httpclient.sendBufferSize=32 WebSocketTextTest @@ -65,7 +66,8 @@ public class WebSocketExtendedTest { // FIXME ensure subsequent (sendText/Binary, false) only CONTINUATIONs - @Test(dataProvider = "binary") + @ParameterizedTest + @MethodSource("binary") public void binary(ByteBuffer expected) throws IOException, InterruptedException { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); @@ -76,15 +78,16 @@ public class WebSocketExtendedTest { ws.sendBinary(expected.duplicate(), true).join(); ws.abort(); List frames = server.readFrames(); - assertEquals(frames.size(), 1); + assertEquals(1, frames.size()); DummyWebSocketServer.DecodedFrame f = frames.get(0); assertTrue(f.last()); - assertEquals(f.opcode(), Frame.Opcode.BINARY); - assertEquals(f.data(), expected); + assertEquals(Frame.Opcode.BINARY, f.opcode()); + assertEquals(expected, f.data()); } } - @Test(dataProvider = "pingPong") + @ParameterizedTest + @MethodSource("pingPongSizes") public void ping(ByteBuffer expected) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); @@ -95,17 +98,18 @@ public class WebSocketExtendedTest { ws.sendPing(expected.duplicate()).join(); ws.abort(); List frames = server.readFrames(); - assertEquals(frames.size(), 1); + assertEquals(1, frames.size()); DummyWebSocketServer.DecodedFrame f = frames.get(0); - assertEquals(f.opcode(), Frame.Opcode.PING); + assertEquals(Frame.Opcode.PING, f.opcode()); ByteBuffer actual = ByteBuffer.allocate(expected.remaining()); actual.put(f.data()); actual.flip(); - assertEquals(actual, expected); + assertEquals(expected, actual); } } - @Test(dataProvider = "pingPong") + @ParameterizedTest + @MethodSource("pingPongSizes") public void pong(ByteBuffer expected) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); @@ -116,17 +120,18 @@ public class WebSocketExtendedTest { ws.sendPong(expected.duplicate()).join(); ws.abort(); List frames = server.readFrames(); - assertEquals(frames.size(), 1); + assertEquals(1, frames.size()); DummyWebSocketServer.DecodedFrame f = frames.get(0); - assertEquals(f.opcode(), Frame.Opcode.PONG); + assertEquals(Frame.Opcode.PONG, f.opcode()); ByteBuffer actual = ByteBuffer.allocate(expected.remaining()); actual.put(f.data()); actual.flip(); - assertEquals(actual, expected); + assertEquals(expected, actual); } } - @Test(dataProvider = "close") + @ParameterizedTest + @MethodSource("closeArguments") public void close(int statusCode, String reason) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); @@ -137,18 +142,19 @@ public class WebSocketExtendedTest { ws.sendClose(statusCode, reason).join(); ws.abort(); List frames = server.readFrames(); - assertEquals(frames.size(), 1); + assertEquals(1, frames.size()); DummyWebSocketServer.DecodedFrame f = frames.get(0); - assertEquals(f.opcode(), Frame.Opcode.CLOSE); + assertEquals(Frame.Opcode.CLOSE, f.opcode()); ByteBuffer actual = ByteBuffer.allocate(Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH); actual.put(f.data()); actual.flip(); - assertEquals(actual.getChar(), statusCode); - assertEquals(StandardCharsets.UTF_8.decode(actual).toString(), reason); + assertEquals(statusCode, actual.getChar()); + assertEquals(reason, StandardCharsets.UTF_8.decode(actual).toString()); } } - @Test(dataProvider = "text") + @ParameterizedTest + @MethodSource("texts") public void text(String expected) throws Exception { try (DummyWebSocketServer server = new DummyWebSocketServer()) { server.open(); @@ -163,12 +169,11 @@ public class WebSocketExtendedTest { ByteBuffer actual = ByteBuffer.allocate(maxBytes); frames.stream().forEachOrdered(f -> actual.put(f.data())); actual.flip(); - assertEquals(StandardCharsets.UTF_8.decode(actual).toString(), expected); + assertEquals(expected, StandardCharsets.UTF_8.decode(actual).toString()); } } - @DataProvider(name = "pingPong") - public Object[][] pingPongSizes() { + public static Object[][] pingPongSizes() { return new Object[][]{ {bytes( 0)}, {bytes( 1)}, @@ -177,8 +182,7 @@ public class WebSocketExtendedTest { }; } - @DataProvider(name = "close") - public Object[][] closeArguments() { + public static Object[][] closeArguments() { return new Object[][]{ {WebSocket.NORMAL_CLOSURE, utf8String( 0)}, {WebSocket.NORMAL_CLOSURE, utf8String( 1)}, @@ -216,16 +220,14 @@ public class WebSocketExtendedTest { return str.toString(); } - @DataProvider(name = "text") - public Object[][] texts() { + public static Object[][] texts() { return new Object[][]{ {utf8String( 0)}, {utf8String(1024)}, }; } - @DataProvider(name = "binary") - public Object[][] binary() { + public static Object[][] binary() { return new Object[][]{ {bytes( 0)}, {bytes(1024)}, diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java index 46758b2fe6e..a410aa9fe75 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @library /test/lib * @compile SecureSupport.java DummySecureWebSocketServer.java ../ProxyServer.java * @build jdk.test.lib.net.SimpleSSLContext WebSocketProxyTest - * @run testng/othervm + * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,headers @@ -61,16 +61,18 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import jdk.test.lib.net.SimpleSSLContext; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import static java.net.http.HttpClient.newBuilder; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.testng.Assert.assertEquals; -import static org.testng.FileAssert.fail; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class WebSocketProxyTest { @@ -132,8 +134,7 @@ public class WebSocketProxyTest { @Override public String toString() { return "AUTH_TUNNELING_PROXY_SERVER"; } }; - @DataProvider(name = "servers") - public Object[][] servers() { + public static Object[][] servers() { return new Object[][] { { SERVER_WITH_CANNED_DATA, TUNNELING_PROXY_SERVER }, { SERVER_WITH_CANNED_DATA, AUTH_TUNNELING_PROXY_SERVER }, @@ -175,7 +176,8 @@ public class WebSocketProxyTest { return "%s and %s %s".formatted(actual, expected, message); } - @Test(dataProvider = "servers") + @ParameterizedTest + @MethodSource("servers") public void simpleAggregatingBinaryMessages (Function serverSupplier, Supplier proxyServerSupplier) @@ -263,7 +265,7 @@ public class WebSocketProxyTest { .join(); List a = actual.join(); - assertEquals(ofBytes(a), ofBytes(expected), diagnose(a, expected)); + assertEquals(ofBytes(expected), ofBytes(a), diagnose(a, expected)); } } @@ -359,7 +361,7 @@ public class WebSocketProxyTest { } catch (CompletionException expected) { WebSocketHandshakeException e = (WebSocketHandshakeException)expected.getCause(); HttpResponse response = e.getResponse(); - assertEquals(response.statusCode(), 407); + assertEquals(407, response.statusCode()); } } } @@ -398,7 +400,7 @@ public class WebSocketProxyTest { } } - @BeforeMethod + @BeforeEach public void breakBetweenTests() { System.gc(); try {Thread.sleep(100); } catch (InterruptedException x) { /* OK */ } diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java index 43bcb054b7d..2b1df3d7e87 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +27,10 @@ * @library ../access * @build DummyWebSocketServer * java.net.http/jdk.internal.net.http.HttpClientTimerAccess - * @run testng/othervm + * @run junit/othervm * WebSocketTest */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.Authenticator; @@ -63,9 +61,13 @@ import static java.net.http.HttpClient.newBuilder; import static java.net.http.WebSocket.NORMAL_CLOSURE; import static java.nio.charset.StandardCharsets.UTF_8; import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.fail; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; public class WebSocketTest { @@ -264,8 +266,7 @@ public class WebSocketTest { } } - @DataProvider(name = "sequence") - public Object[][] data1() { + public static Object[][] data1() { int[] CLOSE = { 0x81, 0x00, // "" 0x82, 0x00, // [] @@ -292,7 +293,8 @@ public class WebSocketTest { }; } - @Test(dataProvider = "sequence") + @ParameterizedTest + @MethodSource("data1") public void listenerSequentialOrder(int[] binary, long requestSize) throws IOException { @@ -470,8 +472,7 @@ public class WebSocketTest { @Override public String toString() { return "AUTH_SERVER_WITH_CANNED_DATA"; } }; - @DataProvider(name = "servers") - public Object[][] servers() { + public static Object[][] servers() { return new Object[][] { { SERVER_WITH_CANNED_DATA }, { AUTH_SERVER_WITH_CANNED_DATA }, @@ -507,7 +508,8 @@ public class WebSocketTest { return "%s and %s %s".formatted(actual, expected, message); } - @Test(dataProvider = "servers") + @ParameterizedTest + @MethodSource("servers") public void simpleAggregatingBinaryMessages (Function serverSupplier) throws IOException @@ -600,14 +602,15 @@ public class WebSocketTest { .join(); try { List a = actual.join(); - assertEquals(ofBytes(a), ofBytes(expected), diagnose(a, expected)); + assertEquals(ofBytes(expected), ofBytes(a), diagnose(a, expected)); } finally { webSocket.abort(); } } } - @Test(dataProvider = "servers") + @ParameterizedTest + @MethodSource("servers") public void simpleAggregatingTextMessages (Function serverSupplier) throws IOException @@ -683,7 +686,7 @@ public class WebSocketTest { .join(); try { List a = actual.join(); - assertEquals(a, expected); + assertEquals(expected, a); } finally { webSocket.abort(); } @@ -694,7 +697,8 @@ public class WebSocketTest { * Exercises the scenario where requests for more messages are made prior to * completing the returned CompletionStage instances. */ - @Test(dataProvider = "servers") + @ParameterizedTest + @MethodSource("servers") public void aggregatingTextMessages (Function serverSupplier) throws IOException @@ -784,7 +788,7 @@ public class WebSocketTest { .join(); try { List a = actual.join(); - assertEquals(a, expected); + assertEquals(expected, a); } finally { webSocket.abort(); } @@ -853,7 +857,7 @@ public class WebSocketTest { } catch (CompletionException expected) { WebSocketHandshakeException e = (WebSocketHandshakeException)expected.getCause(); HttpResponse response = e.getResponse(); - assertEquals(response.statusCode(), 401); + assertEquals(401, response.statusCode()); } } } diff --git a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/HeaderWriterTest.java b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/HeaderWriterTest.java index 0e55eaf521f..59a66591c93 100644 --- a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/HeaderWriterTest.java +++ b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/HeaderWriterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ package jdk.internal.net.http.websocket; -import org.testng.annotations.Test; import jdk.internal.net.http.websocket.Frame.HeaderWriter; import jdk.internal.net.http.websocket.Frame.Opcode; @@ -32,10 +31,12 @@ import java.util.OptionalInt; import static java.util.OptionalInt.empty; import static java.util.OptionalInt.of; -import static org.testng.Assert.assertEquals; import static jdk.internal.net.http.websocket.TestSupport.assertThrows; import static jdk.internal.net.http.websocket.TestSupport.forEachPermutation; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class HeaderWriterTest { private long cases, frames; @@ -109,7 +110,7 @@ public class HeaderWriterTest { ByteBuffer actual = ByteBuffer.allocate(Frame.MAX_HEADER_SIZE_BYTES + 2); writer.write(actual); actual.flip(); - assertEquals(actual, expected); + assertEquals(expected, actual); }); } } diff --git a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java index 7eb892f12ea..cb59b9f7213 100644 --- a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java +++ b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MaskerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,17 @@ package jdk.internal.net.http.websocket; -import org.testng.annotations.Test; - import java.nio.ByteBuffer; import java.security.SecureRandom; import java.util.stream.IntStream; -import static org.testng.Assert.assertEquals; import static jdk.internal.net.http.websocket.Frame.Masker.applyMask; import static jdk.internal.net.http.websocket.TestSupport.forEachBufferPartition; import static jdk.internal.net.http.websocket.TestSupport.fullCopy; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class MaskerTest { private static final SecureRandom random = new SecureRandom(); @@ -98,14 +98,14 @@ public class MaskerTest { int dstRemaining = dstCopy.remaining(); int masked = Math.min(srcRemaining, dstRemaining); // 1. position check - assertEquals(src.position(), srcCopy.position() + masked); - assertEquals(dst.position(), dstCopy.position() + masked); + assertEquals(srcCopy.position() + masked, src.position()); + assertEquals(dstCopy.position() + masked, dst.position()); // 2. masking check src.position(srcCopy.position()); dst.position(dstCopy.position()); for (; src.hasRemaining() && dst.hasRemaining(); offset = (offset + 1) & 3) { - assertEquals(dst.get(), src.get() ^ maskBytes[offset]); + assertEquals(src.get() ^ maskBytes[offset], dst.get()); } // 3. corruption check // 3.1 src contents haven't changed @@ -113,7 +113,7 @@ public class MaskerTest { int srcLimit = src.limit(); src.clear(); srcCopy.clear(); - assertEquals(src, srcCopy); + assertEquals(srcCopy, src); src.limit(srcLimit).position(srcPosition); // restore src // 3.2 dst leading and trailing regions' contents haven't changed int dstPosition = dst.position(); @@ -122,11 +122,11 @@ public class MaskerTest { // leading dst.position(0).limit(dstInitialPosition); dstCopy.position(0).limit(dstInitialPosition); - assertEquals(dst, dstCopy); + assertEquals(dstCopy, dst); // trailing dst.limit(dst.capacity()).position(dstLimit); dstCopy.limit(dst.capacity()).position(dstLimit); - assertEquals(dst, dstCopy); + assertEquals(dstCopy, dst); // restore dst dst.position(dstPosition).limit(dstLimit); return offset; diff --git a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MessageQueueTest.java b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MessageQueueTest.java index 61503f0e235..73cab76df28 100644 --- a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MessageQueueTest.java +++ b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/MessageQueueTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,6 @@ package jdk.internal.net.http.websocket; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -46,10 +43,14 @@ import java.util.function.BiConsumer; import java.util.function.Supplier; import static jdk.internal.net.http.websocket.MessageQueue.effectiveCapacityOf; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * A unit test for MessageQueue. The test is aware of the details of the queue @@ -59,7 +60,6 @@ public class MessageQueueTest { private static final Random r = new SecureRandom(); - @DataProvider(name = "illegalCapacities") public static Object[][] illegalCapacities() { return new Object[][]{ new Object[]{Integer.MIN_VALUE}, @@ -69,17 +69,20 @@ public class MessageQueueTest { }; } - @Test(dataProvider = "illegalCapacities") + @ParameterizedTest + @MethodSource("illegalCapacities") public void illegalCapacity(int n) { assertThrows(IllegalArgumentException.class, () -> new MessageQueue(n)); } - @Test(dataProvider = "capacities") + @ParameterizedTest + @MethodSource("capacities") public void emptiness(int n) { assertTrue(new MessageQueue(n).isEmpty()); } - @Test(dataProvider = "capacities") + @ParameterizedTest + @MethodSource("capacities") public void fullness(int n) throws IOException { MessageQueue q = new MessageQueue(n); int cap = effectiveCapacityOf(n); @@ -97,7 +100,7 @@ public class MessageQueueTest { for (int i = 0; i < cap; i++) { Message expected = referenceQueue.remove(); Message actual = new Remover().removeFrom(q); - assertEquals(actual, expected); + assertEquals(expected, actual); } } @@ -144,7 +147,8 @@ public class MessageQueueTest { action, future); } - @Test(dataProvider = "capacities") + @ParameterizedTest + @MethodSource("capacities") public void caterpillarWalk(int n) throws IOException { // System.out.println("n: " + n); int cap = effectiveCapacityOf(n); @@ -164,7 +168,7 @@ public class MessageQueueTest { for (int i = 0; i < p; i++) { Message expected = referenceQueue.remove(); Message actual = remover.removeFrom(q); - assertEquals(actual, expected); + assertEquals(expected, actual); } assertTrue(q.isEmpty()); } @@ -243,7 +247,7 @@ public class MessageQueueTest { f.get(); // Just to check for exceptions } consumer.get(); // Waiting for consumer to collect all the messages - assertEquals(actualList.size(), expectedList.size()); + assertEquals(expectedList.size(), actualList.size()); for (Message m : expectedList) { assertTrue(actualList.remove(m)); } @@ -257,7 +261,8 @@ public class MessageQueueTest { } } - @Test(dataProvider = "capacities") + @ParameterizedTest + @MethodSource("capacities") public void testSingleThreaded(int n) throws IOException { Queue referenceQueue = new LinkedList<>(); MessageQueue q = new MessageQueue(n); @@ -271,13 +276,12 @@ public class MessageQueueTest { for (int i = 0; i < cap; i++) { Message expected = referenceQueue.remove(); Message actual = new Remover().removeFrom(q); - assertEquals(actual, expected); + assertEquals(expected, actual); } assertTrue(q.isEmpty()); } - @DataProvider(name = "capacities") - public Object[][] capacities() { + public static Object[][] capacities() { return new Object[][]{ new Object[]{ 1}, new Object[]{ 2}, diff --git a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/ReaderTest.java b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/ReaderTest.java index c53ac88f69c..c7b1ab80fbd 100644 --- a/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/ReaderTest.java +++ b/test/jdk/java/net/httpclient/websocket/java.net.http/jdk/internal/net/http/websocket/ReaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ package jdk.internal.net.http.websocket; -import org.testng.annotations.Test; import jdk.internal.net.http.websocket.Frame.Opcode; import java.nio.ByteBuffer; @@ -35,10 +34,12 @@ import java.util.function.IntUnaryOperator; import static java.util.OptionalInt.empty; import static java.util.OptionalInt.of; -import static org.testng.Assert.assertEquals; import static jdk.internal.net.http.websocket.TestSupport.assertThrows; import static jdk.internal.net.http.websocket.TestSupport.forEachBufferPartition; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ReaderTest { private long cases, frames; @@ -128,15 +129,15 @@ public class ReaderTest { for (ByteBuffer b : buffers) { r.readFrame(b, c); } - assertEquals(fin, c.fin()); - assertEquals(rsv1, c.rsv1()); - assertEquals(rsv2, c.rsv2()); - assertEquals(rsv3, c.rsv3()); - assertEquals(opcode, c.opcode()); - assertEquals(mask.isPresent(), c.mask()); - assertEquals(payloadLen, c.payloadLen()); - assertEquals(mask, c.maskingKey()); - assertEquals(payloadLen == 0, c.isEndFrame()); + assertEquals(c.fin(), fin); + assertEquals(c.rsv1(), rsv1); + assertEquals(c.rsv2(), rsv2); + assertEquals(c.rsv3(), rsv3); + assertEquals(c.opcode(), opcode); + assertEquals(c.mask(), mask.isPresent()); + assertEquals(c.payloadLen(), payloadLen); + assertEquals(c.maskingKey(), mask); + assertEquals(c.isEndFrame(), payloadLen == 0); }); } diff --git a/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java b/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java index 787486dbd84..c8e4faa1ad3 100644 --- a/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java +++ b/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @summary Basic sanity checks for WebSocket URI from the Builder * @compile ../DummyWebSocketServer.java ../../ProxyServer.java - * @run testng/othervm WSSanityTest + * @run junit/othervm WSSanityTest */ import java.io.IOException; @@ -38,20 +38,21 @@ import java.net.URI; import java.util.List; import java.net.http.HttpClient; import java.net.http.WebSocket; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; public class WSSanityTest { - URI wsURI; - DummyWebSocketServer webSocketServer; - InetSocketAddress proxyAddress; + private static URI wsURI; + private static DummyWebSocketServer webSocketServer; + private static InetSocketAddress proxyAddress; - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { ProxyServer proxyServer = new ProxyServer(0, true); proxyAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), proxyServer.getPort()); @@ -63,8 +64,8 @@ public class WSSanityTest { System.out.println("DummyWebSocketServer: " + wsURI); } - @AfterTest - public void teardown() { + @AfterAll + public static void teardown() { webSocketServer.close(); } @@ -75,8 +76,7 @@ public class WSSanityTest { T run() throws Exception; } - @DataProvider(name = "passingScenarios") - public Object[][] passingScenarios() { + public static Object[][] passingScenarios() { HttpClient noProxyClient = HttpClient.newHttpClient(); return new Object[][]{ { (ExceptionAction)() -> { @@ -146,14 +146,15 @@ public class WSSanityTest { HttpClient client = HttpClient.newBuilder().proxy(ps).build(); client.newWebSocketBuilder() .buildAsync(wsURI, noOpListener).get().abort(); - assertEquals(ps.count(), 1); // ps.select only invoked once + assertEquals(1, ps.count()); // ps.select only invoked once return null; }, "7" }, }; } - @Test(dataProvider = "passingScenarios") + @ParameterizedTest + @MethodSource("passingScenarios") public void testScenarios(ExceptionAction action, String dataProviderId) throws Exception { From 0668dab54568a08d49c8c10a7efc4d06ca191083 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Thu, 5 Mar 2026 12:26:37 +0000 Subject: [PATCH 055/655] 8379114: HttpServer path prefix matching incorrectly matches paths that are not slash-prefixed Reviewed-by: dfuchs --- .../sun/net/httpserver/ContextList.java | 51 +++---- .../ContextPathMatcherPathPrefixTest.java | 139 +++++++++++++++--- .../ContextPathMatcherStringPrefixTest.java | 40 ++--- 3 files changed, 162 insertions(+), 68 deletions(-) diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java index 6393ca34798..14a07b3a677 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ContextList.java @@ -186,38 +186,31 @@ class ContextList { */ PATH_PREFIX((contextPath, requestPath) -> { - // Fast-path for `/` - if ("/".equals(contextPath)) { + // Does the request path prefix match? + if (!requestPath.startsWith(contextPath)) { + return false; + } + + // Is it an exact match? + int contextPathLength = contextPath.length(); + if (requestPath.length() == contextPathLength) { return true; } - // Does the request path prefix match? - if (requestPath.startsWith(contextPath)) { - - // Is it an exact match? - int contextPathLength = contextPath.length(); - if (requestPath.length() == contextPathLength) { - return true; - } - - // Is it a path-prefix match? - assert contextPathLength > 0; - return - // Case 1: The request path starts with the context - // path, but the context path has an extra path - // separator suffix. For instance, the context path is - // `/foo/` and the request path is `/foo/bar`. - contextPath.charAt(contextPathLength - 1) == '/' || - // Case 2: The request path starts with the - // context path, but the request path has an - // extra path separator suffix. For instance, - // context path is `/foo` and the request path - // is `/foo/` or `/foo/bar`. - requestPath.charAt(contextPathLength) == '/'; - - } - - return false; + // Is it a path-prefix match? + assert contextPathLength > 0; + return + // Case 1: The request path starts with the context + // path, but the context path has an extra path + // separator suffix. For instance, the context path is + // `/foo/` and the request path is `/foo/bar`. + contextPath.charAt(contextPathLength - 1) == '/' || + // Case 2: The request path starts with the + // context path, but the request path has an + // extra path separator suffix. For instance, + // context path is `/foo` and the request path + // is `/foo/` or `/foo/bar`. + requestPath.charAt(contextPathLength) == '/'; }); diff --git a/test/jdk/com/sun/net/httpserver/ContextPathMatcherPathPrefixTest.java b/test/jdk/com/sun/net/httpserver/ContextPathMatcherPathPrefixTest.java index e1cff62a45f..6b260636585 100644 --- a/test/jdk/com/sun/net/httpserver/ContextPathMatcherPathPrefixTest.java +++ b/test/jdk/com/sun/net/httpserver/ContextPathMatcherPathPrefixTest.java @@ -23,21 +23,30 @@ import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; + +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.URI; +import java.net.Socket; import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static java.net.http.HttpClient.Builder.NO_PROXY; import org.junit.jupiter.api.AfterAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -89,29 +98,88 @@ public class ContextPathMatcherPathPrefixTest { @Test void testContextPathAtRoot() throws Exception { + // Repeating all cases with both known (GET) and unknown (DOH) request methods to stress both paths try (var infra = new Infra("/")) { - infra.expect(200, "/foo", "/foo/", "/foo/bar", "/foobar"); + // 200 + infra.expect(200, "GET /foo"); + infra.expect(200, "GET /foo/"); + infra.expect(200, "GET /foo/bar"); + infra.expect(200, "GET /foobar"); + infra.expect(200, "DOH /foo"); + infra.expect(200, "DOH /foo/"); + infra.expect(200, "DOH /foo/bar"); + infra.expect(200, "DOH /foobar"); + // 404 + infra.expect(404, "GET foo"); + infra.expect(404, "GET *"); + infra.expect(404, "GET "); + infra.expect(404, "DOH foo"); + infra.expect(404, "DOH *"); + infra.expect(404, "DOH "); + // 400 + infra.expect(400, "GET"); + infra.expect(400, "DOH"); } } @Test void testContextPathAtSubDir() throws Exception { + // Repeating all cases with both known (GET) and unknown (DOH) request methods to stress both paths try (var infra = new Infra("/foo")) { - infra.expect(200, "/foo", "/foo/", "/foo/bar"); - infra.expect(404, "/foobar"); + // 200 + infra.expect(200, "GET /foo"); + infra.expect(200, "GET /foo/"); + infra.expect(200, "GET /foo/bar"); + infra.expect(200, "DOH /foo"); + infra.expect(200, "DOH /foo/"); + infra.expect(200, "DOH /foo/bar"); + // 404 + infra.expect(404, "GET /foobar"); // Differs from string prefix matching! + infra.expect(404, "GET foo"); + infra.expect(404, "GET *"); + infra.expect(404, "GET "); + infra.expect(404, "DOH /foobar"); // Differs from string prefix matching! + infra.expect(404, "DOH foo"); + infra.expect(404, "DOH *"); + infra.expect(404, "DOH "); + // 400 + infra.expect(400, "GET"); + infra.expect(400, "DOH"); } } @Test void testContextPathAtSubDirWithTrailingSlash() throws Exception { + // Repeating all cases with both known (GET) and unknown (DOH) request methods to stress both paths try (var infra = new Infra("/foo/")) { - infra.expect(200, "/foo/", "/foo/bar"); - infra.expect(404, "/foo", "/foobar"); + // 200 + infra.expect(200, "GET /foo/"); + infra.expect(200, "GET /foo/bar"); + infra.expect(200, "DOH /foo/"); + infra.expect(200, "DOH /foo/bar"); + // 404 + infra.expect(404, "GET /foo"); + infra.expect(404, "GET /foobar"); + infra.expect(404, "GET foo"); + infra.expect(404, "GET *"); + infra.expect(404, "GET "); + infra.expect(404, "DOH /foo"); + infra.expect(404, "DOH /foobar"); + infra.expect(404, "DOH foo"); + infra.expect(404, "DOH *"); + infra.expect(404, "DOH "); + // 400 + infra.expect(400, "GET"); + infra.expect(400, "DOH"); } } protected static final class Infra implements AutoCloseable { + /** Charset used for network and file I/O. */ + private static final Charset CHARSET = StandardCharsets.US_ASCII; + + /** Socket address the server will bind to. */ private static final InetSocketAddress LO_SA_0 = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); @@ -128,22 +196,51 @@ public class ContextPathMatcherPathPrefixTest { this.contextPath = contextPath; } - protected void expect(int statusCode, String... requestPaths) throws Exception { - for (String requestPath : requestPaths) { - var requestURI = URI.create("http://%s:%s%s".formatted( - server.getAddress().getHostString(), - server.getAddress().getPort(), - requestPath)); - var request = HttpRequest.newBuilder(requestURI).build(); - var response = CLIENT.send(request, HttpResponse.BodyHandlers.discarding()); - assertEquals( - statusCode, response.statusCode(), - "unexpected status code " + Map.of( - "contextPath", contextPath, - "requestPath", requestPath)); + protected void expect(int statusCode, String requestLinePrefix) { + try { + expect0(statusCode, requestLinePrefix); + } catch (Throwable exception) { + var extendedMessage = exception.getMessage() + " " + Map.of( + "contextPath", contextPath, + "requestLinePrefix", requestLinePrefix); + var extendedException = new RuntimeException(extendedMessage); + extendedException.setStackTrace(exception.getStackTrace()); + throw extendedException; } } + private void expect0(int statusCode, String requestLinePrefix) throws IOException { + + // Connect to the server + try (Socket socket = new Socket()) { + socket.connect(server.getAddress()); + + // Obtain the I/O streams + try (OutputStream outputStream = socket.getOutputStream(); + InputStream inputStream = socket.getInputStream(); + BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream, CHARSET))) { + + // Write the request + byte[] requestBytes = String + // `Connection: close` is required for `BufferedReader::readLine` to work. + .format("%s HTTP/1.1\r\nConnection: close\r\n\r\n", requestLinePrefix) + .getBytes(CHARSET); + outputStream.write(requestBytes); + outputStream.flush(); + + // Read the response status code + String statusLine = inputReader.readLine(); + assertNotNull(statusLine, "Unexpected EOF while reading status line"); + Matcher statusLineMatcher = Pattern.compile("^HTTP/1\\.1 (\\d+) .+$").matcher(statusLine); + assertTrue(statusLineMatcher.matches(), "Couldn't match status line: \"" + statusLine + "\""); + assertEquals(statusCode, Integer.parseInt(statusLineMatcher.group(1))); + + } + + } + + } + @Override public void close() { server.stop(0); diff --git a/test/jdk/com/sun/net/httpserver/ContextPathMatcherStringPrefixTest.java b/test/jdk/com/sun/net/httpserver/ContextPathMatcherStringPrefixTest.java index 3f3008a8531..4faa1463e1b 100644 --- a/test/jdk/com/sun/net/httpserver/ContextPathMatcherStringPrefixTest.java +++ b/test/jdk/com/sun/net/httpserver/ContextPathMatcherStringPrefixTest.java @@ -36,28 +36,32 @@ import org.junit.jupiter.api.Test; class ContextPathMatcherStringPrefixTest extends ContextPathMatcherPathPrefixTest { - @Test - @Override - void testContextPathAtRoot() throws Exception { - try (var infra = new Infra("/")) { - infra.expect(200, "/foo", "/foo/", "/foo/bar", "/foobar"); - } - } - @Test @Override void testContextPathAtSubDir() throws Exception { + // Repeating all cases with both known (GET) and unknown (DOH) request methods to stress both paths try (var infra = new Infra("/foo")) { - infra.expect(200, "/foo", "/foo/", "/foo/bar", "/foobar"); - } - } - - @Test - @Override - void testContextPathAtSubDirWithTrailingSlash() throws Exception { - try (var infra = new Infra("/foo/")) { - infra.expect(200, "/foo/", "/foo/bar"); - infra.expect(404, "/foo", "/foobar"); + // 200 + infra.expect(200, "GET /foo"); + infra.expect(200, "GET /foo/"); + infra.expect(200, "GET /foo/bar"); + infra.expect(200, "GET /foobar"); // Differs from path prefix matching! + infra.expect(200, "DOH /foo"); + infra.expect(200, "DOH /foo/"); + infra.expect(200, "DOH /foo/bar"); + infra.expect(200, "DOH /foobar"); // Differs from path prefix matching! + // 404 + infra.expect(404, "GET /"); + infra.expect(404, "GET foo"); + infra.expect(404, "GET *"); + infra.expect(404, "GET "); + infra.expect(404, "DOH /"); + infra.expect(404, "DOH foo"); + infra.expect(404, "DOH *"); + infra.expect(404, "DOH "); + // 400 + infra.expect(400, "GET"); + infra.expect(400, "DOH"); } } From 4d9d2c352b9daa8bdecea5303f49f2496c127115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 5 Mar 2026 14:15:08 +0000 Subject: [PATCH 056/655] 8284315: DocTrees.getElement is inconsistent with Elements.getTypeElement Reviewed-by: jlahoda, vromero --- .../classes/com/sun/source/util/DocTrees.java | 25 +-- .../com/sun/tools/javac/api/JavacTrees.java | 142 +++++++++--------- .../doclets/toolkit/util/CommentHelper.java | 7 +- .../jdk/javadoc/internal/doclint/Checker.java | 12 +- .../javadoc/doclet/testSeeTag/TestSeeTag.java | 10 +- .../tools/doclint/ReferenceTest.java | 2 +- .../langtools/tools/doclint/ReferenceTest.out | 14 +- .../tools/javac/doctree/ReferenceTest.java | 78 ++++++++-- 8 files changed, 184 insertions(+), 106 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java index 45a452bd0dd..44d9bd89917 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -195,23 +195,30 @@ public abstract class DocTrees extends Trees { /** * Returns the language model element referred to by the leaf node of the given - * {@link DocTreePath}, or {@code null} if unknown. + * {@link DocTreePath}, or {@code null} if the leaf node of {@code path} does + * not refer to an element. + * * @param path the path for the tree node - * @return the element + * @return the referenced element, or null + * @see #getType(DocTreePath) */ public abstract Element getElement(DocTreePath path); /** * Returns the language model type referred to by the leaf node of the given - * {@link DocTreePath}, or {@code null} if unknown. This method usually - * returns the same value as {@code getElement(path).asType()} for a - * {@code path} argument for which {@link #getElement(DocTreePath)} returns - * a non-null value, but may return a type that includes additional - * information, such as a parameterized generic type instead of a raw type. + * {@link DocTreePath}, or {@code null} if the leaf node of {@code path} does + * not refer to a type. + * + *

If {@link #getElement(DocTreePath)} returns a non-null value for a given {@code path} + * argument, this method usally returns the same value as {@code getElement(path).asType()}. + * However, there are cases where the returned type includes additional information, + * such as a parameterized generic type instead of a raw type. In other cases, such as with + * primitive or array types, the returned type may not have a corresponding element returned + * by {@code getElement(DocTreePath)}.

* * @param path the path for the tree node * @return the referenced type, or null - * + * @see #getElement(DocTreePath) * @since 15 */ public abstract TypeMirror getType(DocTreePath path); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index 6bc5d358b6f..ecd7f5b101a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -354,22 +354,28 @@ public class JavacTrees extends DocTrees { DocTree tree = path.getLeaf(); if (tree instanceof DCReference dcReference) { JCTree qexpr = dcReference.qualifierExpression; - if (qexpr != null) { + + // Forward references with explicit module name to getElement + if (qexpr != null && dcReference.moduleName == null) { + + Env env = getAttrContext(path.getTreePath()); Log.DeferredDiagnosticHandler deferredDiagnosticHandler = log.new DeferredDiagnosticHandler(); + JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); + try { - Env env = getAttrContext(path.getTreePath()); - JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); - try { - Type t = attr.attribType(dcReference.qualifierExpression, env); - if (t != null && !t.isErroneous()) { + Type t = attr.attribType(dcReference.qualifierExpression, env); + if (t != null && !t.isErroneous()) { + if (dcReference.memberName != null) { + Symbol sym = resolveMember(t, (Name) dcReference.memberName, dcReference, env); + return sym == null ? null : sym.type; + } else { return t; } - } finally { - log.useSource(prevSource); } } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file return null; } finally { + log.useSource(prevSource); log.popDiagnosticHandler(deferredDiagnosticHandler); } } @@ -426,14 +432,12 @@ public class JavacTrees extends DocTrees { memberName = (Name) ref.memberName; } else { // Check if qualifierExpression is a type or package, using the methods javac provides. - // If no module name is given we check if qualifierExpression identifies a type. - // If that fails or we have a module name, use that to resolve qualifierExpression to - // a package or type. - Type t = ref.moduleName == null ? attr.attribType(ref.qualifierExpression, env) : null; + Type t = attr.attribType(ref.qualifierExpression, env); - if (t == null || t.isErroneous()) { - JCCompilationUnit toplevel = - treeMaker.TopLevel(List.nil()); + if (t == null || t.isErroneous() || + (ref.moduleName != null && !mdlsym.equals(elements.getModuleOf(t.asElement())))) { + + JCCompilationUnit toplevel = treeMaker.TopLevel(List.nil()); toplevel.modle = mdlsym; toplevel.packge = mdlsym.unnamedPackage; Symbol sym = attr.attribIdent(ref.qualifierExpression, toplevel); @@ -447,10 +451,6 @@ public class JavacTrees extends DocTrees { if ((sym.kind == PCK || sym.kind == TYP) && sym.exists()) { tsym = (TypeSymbol) sym; memberName = (Name) ref.memberName; - if (sym.kind == PCK && memberName != null) { - //cannot refer to a package "member" - return null; - } } else { if (modules.modulesInitialized() && ref.moduleName == null && ref.memberName == null) { // package/type does not exist, check if there is a matching module @@ -470,64 +470,22 @@ public class JavacTrees extends DocTrees { } } } else { - Type e = t; - // If this is an array type convert to element type - while (e instanceof ArrayType arrayType) - e = arrayType.elemtype; - tsym = e.tsym; + tsym = switch (t.getKind()) { + case DECLARED, TYPEVAR, PACKAGE, MODULE -> t.tsym; + default -> null; + }; memberName = (Name) ref.memberName; } } if (memberName == null) { return tsym; - } else if (tsym == null || tsym.getKind() == ElementKind.PACKAGE || tsym.getKind() == ElementKind.MODULE) { - return null; // Non-null member name in non-class context - } - - if (tsym.type.isPrimitive()) { + } else if (tsym == null) { return null; } - final List paramTypes; - if (ref.paramTypes == null) - paramTypes = null; - else { - ListBuffer lb = new ListBuffer<>(); - for (List l = (List) ref.paramTypes; l.nonEmpty(); l = l.tail) { - JCTree tree = l.head; - Type t = attr.attribType(tree, env); - lb.add(t); - } - paramTypes = lb.toList(); - } + return resolveMember(tsym.type, memberName, ref, env); - ClassSymbol sym = (ClassSymbol) types.skipTypeVars(tsym.type, false).tsym; - boolean explicitType = ref.qualifierExpression != null; - Symbol msym = (memberName == sym.name) - ? findConstructor(sym, paramTypes, true) - : findMethod(sym, memberName, paramTypes, true, explicitType); - - if (msym == null) { - msym = (memberName == sym.name) - ? findConstructor(sym, paramTypes, false) - : findMethod(sym, memberName, paramTypes, false, explicitType); - } - - if (paramTypes != null) { - // explicit (possibly empty) arg list given, so cannot be a field - return msym; - } - - VarSymbol vsym = (ref.paramTypes != null) ? null : findField(sym, memberName, explicitType); - // prefer a field over a method with no parameters - if (vsym != null && - (msym == null || - types.isSubtypeUnchecked(vsym.enclClass().asType(), msym.enclClass().asType()))) { - return vsym; - } else { - return msym; - } } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file return null; } finally { @@ -536,6 +494,54 @@ public class JavacTrees extends DocTrees { } } + private Symbol resolveMember(Type type, Name memberName, DCReference ref, Env env) { + + if (type.isPrimitive() || type.getKind() == TypeKind.PACKAGE || type.getKind() == TypeKind.MODULE) { + return null; + } + + final List paramTypes; + if (ref.paramTypes == null) + paramTypes = null; + else { + ListBuffer lb = new ListBuffer<>(); + for (List l = (List) ref.paramTypes; l.nonEmpty(); l = l.tail) { + JCTree tree = l.head; + Type t = attr.attribType(tree, env); + lb.add(t); + } + paramTypes = lb.toList(); + } + + // skipTypeVars conversion below is needed if type is itself a type variable + ClassSymbol sym = (ClassSymbol) types.skipTypeVars(type, false).tsym; + boolean explicitType = ref.qualifierExpression != null; + Symbol msym = (memberName == sym.name) + ? findConstructor(sym, paramTypes, true) + : findMethod(sym, memberName, paramTypes, true, explicitType); + + if (msym == null) { + msym = (memberName == sym.name) + ? findConstructor(sym, paramTypes, false) + : findMethod(sym, memberName, paramTypes, false, explicitType); + } + + if (paramTypes != null) { + // explicit (possibly empty) arg list given, so cannot be a field + return msym; + } + + VarSymbol vsym = (ref.paramTypes != null) ? null : findField(sym, memberName, explicitType); + // prefer a field over a method with no parameters + if (vsym != null && + (msym == null || + types.isSubtypeUnchecked(vsym.enclClass().asType(), msym.enclClass().asType()))) { + return vsym; + } else { + return msym; + } + } + private Symbol attributeParamIdentifier(TreePath path, DCParam paramTag) { Symbol javadocSymbol = getElement(path); if (javadocSymbol == null) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index 30aa86aea71..3d300b77073 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,10 +136,7 @@ public class CommentHelper { return null; } DocTrees doctrees = configuration.docEnv.getDocTrees(); - // Workaround for JDK-8284193 - // DocTrees.getElement(DocTreePath) returns javac-internal Symbols - var e = doctrees.getElement(docTreePath); - return e == null || e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED ? null : e; + return doctrees.getElement(docTreePath); } public TypeMirror getType(ReferenceTree rtree) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index b5399d0fef9..90b371a8a15 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1006,11 +1006,11 @@ public class Checker extends DocTreePathScanner { public Void visitReference(ReferenceTree tree, Void ignore) { // Exclude same-file anchor links from reference checks if (!tree.getSignature().startsWith("##")) { - Element e = env.trees.getElement(getCurrentPath()); - if (e == null) { - reportBadReference(tree); - } else if ((inLink || inSee) - && e.getKind() == ElementKind.CLASS && e.asType().getKind() != TypeKind.DECLARED) { + if (inLink || inSee) { + if (env.trees.getElement(getCurrentPath()) == null) { + reportBadReference(tree); + } + } else if (env.trees.getType(getCurrentPath()) == null) { reportBadReference(tree); } } diff --git a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java index f3294f6647c..57854396cf4 100644 --- a/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSeeTag/TestSeeTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 8017191 8182765 8200432 8239804 8250766 8262992 8281944 8307377 + * 8284315 * @summary Javadoc is confused by at-link to imported classes outside of the set of generated packages * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -103,7 +104,12 @@ public class TestSeeTag extends JavadocTester {
See Also: