mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-07 22:50:49 +00:00
Merge branch 'master' of http://github.com/openjdk/jdk into JDK-8370691
This commit is contained in:
commit
dc321a71bb
@ -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
|
||||
|
||||
@ -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<uint8_t>(pack(d)), /*isMerge*/true, /*isFloat*/true);
|
||||
_sve_cpy(Zd, T, Pg, checked_cast<uint8_t>(pack(d)), /*isMerge*/true, /*isFloat*/true);
|
||||
}
|
||||
|
||||
// SVE conditionally select elements from two vectors
|
||||
|
||||
@ -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<dst>.2d, #0`.
|
||||
// On AArch64, Z and V registers alias in the low 128 bits, so V<dst> is
|
||||
// the low 128 bits of Z<dst>. A write to V<dst> also clears all bits of
|
||||
// Z<dst> above 128, so this `movi` instruction effectively zeroes the
|
||||
// entire Z<dst> 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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -95,7 +95,7 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
"Use simplest and shortest implementation for array equals") \
|
||||
product(bool, UseSIMDForBigIntegerShiftIntrinsics, true, \
|
||||
"Use SIMD instructions for left/right shift of BigInteger") \
|
||||
product(bool, UseSIMDForSHA3Intrinsic, true, \
|
||||
product(bool, UseSIMDForSHA3Intrinsic, false, \
|
||||
"Use SIMD SHA3 instructions for SHA3 intrinsic") \
|
||||
product(bool, AvoidUnalignedAccesses, false, \
|
||||
"Avoid generating unaligned memory accesses") \
|
||||
|
||||
@ -11876,16 +11876,13 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_sha512_implCompress = generate_sha512_implCompress(StubId::stubgen_sha512_implCompress_id);
|
||||
StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(StubId::stubgen_sha512_implCompressMB_id);
|
||||
}
|
||||
if (UseSHA3Intrinsics) {
|
||||
|
||||
if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic) {
|
||||
StubRoutines::_double_keccak = generate_double_keccak();
|
||||
if (UseSIMDForSHA3Intrinsic) {
|
||||
StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubId::stubgen_sha3_implCompress_id);
|
||||
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubId::stubgen_sha3_implCompressMB_id);
|
||||
} else {
|
||||
StubRoutines::_sha3_implCompress = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompress_id);
|
||||
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompressMB_id);
|
||||
}
|
||||
StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubId::stubgen_sha3_implCompress_id);
|
||||
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubId::stubgen_sha3_implCompressMB_id);
|
||||
} else if (UseSHA3Intrinsics) {
|
||||
StubRoutines::_sha3_implCompress = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompress_id);
|
||||
StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress_gpr(StubId::stubgen_sha3_implCompressMB_id);
|
||||
}
|
||||
|
||||
if (UsePoly1305Intrinsics) {
|
||||
|
||||
@ -365,16 +365,28 @@ void VM_Version::initialize() {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA && VM_Version::supports_sha3()) {
|
||||
// Auto-enable UseSHA3Intrinsics on hardware with performance benefit.
|
||||
// Note that the evaluation of UseSHA3Intrinsics shows better performance
|
||||
if (UseSHA) {
|
||||
// No need to check VM_Version::supports_sha3(), since a fallback GPR intrinsic implementation is provided.
|
||||
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA3Intrinsics) {
|
||||
// Matches the documented and tested behavior: the -UseSHA option disables all SHA intrinsics.
|
||||
warning("UseSHA3Intrinsics requires that UseSHA is enabled.");
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA3Intrinsics && VM_Version::supports_sha3()) {
|
||||
// Auto-enable UseSIMDForSHA3Intrinsic on hardware with performance benefit.
|
||||
// Note that the evaluation of SHA3 extension Intrinsics shows better performance
|
||||
// on Apple and Qualcomm silicon but worse performance on Neoverse V1 and N2.
|
||||
if (_cpu == CPU_APPLE || _cpu == CPU_QUALCOMM) { // Apple or Qualcomm silicon
|
||||
if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
|
||||
if (FLAG_IS_DEFAULT(UseSIMDForSHA3Intrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseSIMDForSHA3Intrinsic, true);
|
||||
}
|
||||
}
|
||||
} else if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic) {
|
||||
}
|
||||
if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic && !VM_Version::supports_sha3()) {
|
||||
warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -5442,6 +5442,13 @@ void Assembler::pmovsxwd(XMMRegister dst, XMMRegister src) {
|
||||
emit_int16(0x23, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::pmovzxwd(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sse4_1(), "");
|
||||
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
|
||||
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
|
||||
emit_int16(0x33, (0xC0 | encode));
|
||||
}
|
||||
|
||||
void Assembler::vpmovzxbw(XMMRegister dst, Address src, int vector_len) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
InstructionMark im(this);
|
||||
|
||||
@ -1965,6 +1965,7 @@ private:
|
||||
void pmovsxbq(XMMRegister dst, XMMRegister src);
|
||||
void pmovsxbw(XMMRegister dst, XMMRegister src);
|
||||
void pmovsxwd(XMMRegister dst, XMMRegister src);
|
||||
void pmovzxwd(XMMRegister dst, XMMRegister src);
|
||||
void vpmovsxbd(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void vpmovsxbq(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
void vpmovsxbw(XMMRegister dst, XMMRegister src, int vector_len);
|
||||
|
||||
@ -1729,6 +1729,24 @@ void C2_MacroAssembler::reduce_operation_128(BasicType typ, int opcode, XMMRegis
|
||||
default: assert(false, "wrong type");
|
||||
}
|
||||
break;
|
||||
case Op_UMinReductionV:
|
||||
switch (typ) {
|
||||
case T_BYTE: vpminub(dst, dst, src, Assembler::AVX_128bit); break;
|
||||
case T_SHORT: vpminuw(dst, dst, src, Assembler::AVX_128bit); break;
|
||||
case T_INT: vpminud(dst, dst, src, Assembler::AVX_128bit); break;
|
||||
case T_LONG: evpminuq(dst, k0, dst, src, true, Assembler::AVX_128bit); break;
|
||||
default: assert(false, "wrong type");
|
||||
}
|
||||
break;
|
||||
case Op_UMaxReductionV:
|
||||
switch (typ) {
|
||||
case T_BYTE: vpmaxub(dst, dst, src, Assembler::AVX_128bit); break;
|
||||
case T_SHORT: vpmaxuw(dst, dst, src, Assembler::AVX_128bit); break;
|
||||
case T_INT: vpmaxud(dst, dst, src, Assembler::AVX_128bit); break;
|
||||
case T_LONG: evpmaxuq(dst, k0, dst, src, true, Assembler::AVX_128bit); break;
|
||||
default: assert(false, "wrong type");
|
||||
}
|
||||
break;
|
||||
case Op_AddReductionVF: addss(dst, src); break;
|
||||
case Op_AddReductionVD: addsd(dst, src); break;
|
||||
case Op_AddReductionVI:
|
||||
@ -1792,6 +1810,24 @@ void C2_MacroAssembler::reduce_operation_256(BasicType typ, int opcode, XMMRegis
|
||||
default: assert(false, "wrong type");
|
||||
}
|
||||
break;
|
||||
case Op_UMinReductionV:
|
||||
switch (typ) {
|
||||
case T_BYTE: vpminub(dst, src1, src2, vector_len); break;
|
||||
case T_SHORT: vpminuw(dst, src1, src2, vector_len); break;
|
||||
case T_INT: vpminud(dst, src1, src2, vector_len); break;
|
||||
case T_LONG: evpminuq(dst, k0, src1, src2, true, vector_len); break;
|
||||
default: assert(false, "wrong type");
|
||||
}
|
||||
break;
|
||||
case Op_UMaxReductionV:
|
||||
switch (typ) {
|
||||
case T_BYTE: vpmaxub(dst, src1, src2, vector_len); break;
|
||||
case T_SHORT: vpmaxuw(dst, src1, src2, vector_len); break;
|
||||
case T_INT: vpmaxud(dst, src1, src2, vector_len); break;
|
||||
case T_LONG: evpmaxuq(dst, k0, src1, src2, true, vector_len); break;
|
||||
default: assert(false, "wrong type");
|
||||
}
|
||||
break;
|
||||
case Op_AddReductionVI:
|
||||
switch (typ) {
|
||||
case T_BYTE: vpaddb(dst, src1, src2, vector_len); break;
|
||||
@ -2058,7 +2094,11 @@ void C2_MacroAssembler::reduce8B(int opcode, Register dst, Register src1, XMMReg
|
||||
psrldq(vtmp2, 1);
|
||||
reduce_operation_128(T_BYTE, opcode, vtmp1, vtmp2);
|
||||
movdl(vtmp2, src1);
|
||||
pmovsxbd(vtmp1, vtmp1);
|
||||
if (opcode == Op_UMinReductionV || opcode == Op_UMaxReductionV) {
|
||||
pmovzxbd(vtmp1, vtmp1);
|
||||
} else {
|
||||
pmovsxbd(vtmp1, vtmp1);
|
||||
}
|
||||
reduce_operation_128(T_INT, opcode, vtmp1, vtmp2);
|
||||
pextrb(dst, vtmp1, 0x0);
|
||||
movsbl(dst, dst);
|
||||
@ -2135,7 +2175,11 @@ void C2_MacroAssembler::reduce4S(int opcode, Register dst, Register src1, XMMReg
|
||||
reduce_operation_128(T_SHORT, opcode, vtmp1, vtmp2);
|
||||
}
|
||||
movdl(vtmp2, src1);
|
||||
pmovsxwd(vtmp1, vtmp1);
|
||||
if (opcode == Op_UMinReductionV || opcode == Op_UMaxReductionV) {
|
||||
pmovzxwd(vtmp1, vtmp1);
|
||||
} else {
|
||||
pmovsxwd(vtmp1, vtmp1);
|
||||
}
|
||||
reduce_operation_128(T_INT, opcode, vtmp1, vtmp2);
|
||||
pextrw(dst, vtmp1, 0x0);
|
||||
movswl(dst, dst);
|
||||
|
||||
@ -3341,6 +3341,18 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_UMinReductionV:
|
||||
case Op_UMaxReductionV:
|
||||
if (UseAVX == 0) {
|
||||
return false;
|
||||
}
|
||||
if (bt == T_LONG && !VM_Version::supports_avx512vl()) {
|
||||
return false;
|
||||
}
|
||||
if (UseAVX > 2 && size_in_bits == 512 && !VM_Version::supports_avx512vl()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Op_MaxV:
|
||||
case Op_MinV:
|
||||
if (UseSSE < 4 && is_integral_type(bt)) {
|
||||
@ -19371,6 +19383,8 @@ instruct reductionI(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm
|
||||
match(Set dst (XorReductionV src1 src2));
|
||||
match(Set dst (MinReductionV src1 src2));
|
||||
match(Set dst (MaxReductionV src1 src2));
|
||||
match(Set dst (UMinReductionV src1 src2));
|
||||
match(Set dst (UMaxReductionV src1 src2));
|
||||
effect(TEMP vtmp1, TEMP vtmp2);
|
||||
format %{ "vector_reduction_int $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
|
||||
ins_encode %{
|
||||
@ -19392,6 +19406,8 @@ instruct reductionL(rRegL dst, rRegL src1, legVec src2, legVec vtmp1, legVec vtm
|
||||
match(Set dst (XorReductionV src1 src2));
|
||||
match(Set dst (MinReductionV src1 src2));
|
||||
match(Set dst (MaxReductionV src1 src2));
|
||||
match(Set dst (UMinReductionV src1 src2));
|
||||
match(Set dst (UMaxReductionV src1 src2));
|
||||
effect(TEMP vtmp1, TEMP vtmp2);
|
||||
format %{ "vector_reduction_long $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
|
||||
ins_encode %{
|
||||
@ -19411,6 +19427,8 @@ instruct reductionL_avx512dq(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtm
|
||||
match(Set dst (XorReductionV src1 src2));
|
||||
match(Set dst (MinReductionV src1 src2));
|
||||
match(Set dst (MaxReductionV src1 src2));
|
||||
match(Set dst (UMinReductionV src1 src2));
|
||||
match(Set dst (UMaxReductionV src1 src2));
|
||||
effect(TEMP vtmp1, TEMP vtmp2);
|
||||
format %{ "vector_reduction_long $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
|
||||
ins_encode %{
|
||||
@ -19639,6 +19657,8 @@ instruct reductionB(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm
|
||||
match(Set dst (XorReductionV src1 src2));
|
||||
match(Set dst (MinReductionV src1 src2));
|
||||
match(Set dst (MaxReductionV src1 src2));
|
||||
match(Set dst (UMinReductionV src1 src2));
|
||||
match(Set dst (UMaxReductionV src1 src2));
|
||||
effect(TEMP vtmp1, TEMP vtmp2);
|
||||
format %{ "vector_reduction_byte $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
|
||||
ins_encode %{
|
||||
@ -19657,6 +19677,8 @@ instruct reductionB_avx512bw(rRegI dst, rRegI src1, vec src2, vec vtmp1, vec vtm
|
||||
match(Set dst (XorReductionV src1 src2));
|
||||
match(Set dst (MinReductionV src1 src2));
|
||||
match(Set dst (MaxReductionV src1 src2));
|
||||
match(Set dst (UMinReductionV src1 src2));
|
||||
match(Set dst (UMaxReductionV src1 src2));
|
||||
effect(TEMP vtmp1, TEMP vtmp2);
|
||||
format %{ "vector_reduction_byte $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
|
||||
ins_encode %{
|
||||
@ -19678,6 +19700,8 @@ instruct reductionS(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm
|
||||
match(Set dst (XorReductionV src1 src2));
|
||||
match(Set dst (MinReductionV src1 src2));
|
||||
match(Set dst (MaxReductionV src1 src2));
|
||||
match(Set dst (UMinReductionV src1 src2));
|
||||
match(Set dst (UMaxReductionV src1 src2));
|
||||
effect(TEMP vtmp1, TEMP vtmp2);
|
||||
format %{ "vector_reduction_short $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %}
|
||||
ins_encode %{
|
||||
|
||||
36
src/hotspot/os_cpu/aix_ppc/vm_version_aix_ppc.cpp
Normal file
36
src/hotspot/os_cpu/aix_ppc/vm_version_aix_ppc.cpp
Normal file
@ -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 <sys/systemcfg.h>
|
||||
|
||||
int VM_Version::get_dcache_line_size() {
|
||||
return _system_configuration.dcache_line;
|
||||
}
|
||||
|
||||
int VM_Version::get_icache_line_size() {
|
||||
return _system_configuration.icache_line;
|
||||
}
|
||||
44
src/hotspot/os_cpu/linux_ppc/vm_version_linux_ppc.cpp
Normal file
44
src/hotspot/os_cpu/linux_ppc/vm_version_linux_ppc.cpp
Normal file
@ -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 <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@ -73,8 +73,8 @@ void G1BlockOffsetTable::set_offset_array(Atomic<uint8_t>* left, Atomic<uint8_t>
|
||||
|
||||
#ifdef ASSERT
|
||||
void G1BlockOffsetTable::check_address(Atomic<uint8_t>* addr, const char* msg) const {
|
||||
Atomic<uint8_t>* start_addr = const_cast<Atomic<uint8_t>*>(_offset_base + (uintptr_t(_reserved.start()) >> CardTable::card_shift()));
|
||||
Atomic<uint8_t>* end_addr = const_cast<Atomic<uint8_t>*>(_offset_base + (uintptr_t(_reserved.end()) >> CardTable::card_shift()));
|
||||
Atomic<uint8_t>* start_addr = _offset_base + (uintptr_t(_reserved.start()) >> CardTable::card_shift());
|
||||
Atomic<uint8_t>* 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)));
|
||||
|
||||
@ -54,7 +54,7 @@ uint8_t G1BlockOffsetTable::offset_array(Atomic<uint8_t>* addr) const {
|
||||
inline Atomic<uint8_t>* G1BlockOffsetTable::entry_for_addr(const void* const p) const {
|
||||
assert(_reserved.contains(p),
|
||||
"out of bounds access to block offset table");
|
||||
Atomic<uint8_t>* result = const_cast<Atomic<uint8_t>*>(&_offset_base[uintptr_t(p) >> CardTable::card_shift()]);
|
||||
Atomic<uint8_t>* result = &_offset_base[uintptr_t(p) >> CardTable::card_shift()];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -360,6 +360,16 @@ NodeHash::~NodeHash() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Add users of 'n' that match 'predicate' to worklist
|
||||
template <class Predicate>
|
||||
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);
|
||||
}
|
||||
@ -2725,17 +2690,17 @@ 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) {
|
||||
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:
|
||||
@ -2770,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; });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2960,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.
|
||||
@ -2972,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);
|
||||
}
|
||||
}
|
||||
@ -2995,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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -3024,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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -3120,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.
|
||||
@ -3161,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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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 <ScopedFenceType T>
|
||||
class ScopedFenceGeneral: public StackObj {
|
||||
class ScopedFenceGeneral {
|
||||
public:
|
||||
void prefix() {}
|
||||
void postfix() {}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -224,9 +224,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
AnnotatedElement,
|
||||
TypeDescriptor.OfField<Class<?>>,
|
||||
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<T> 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<T> 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();
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 <E> The exception type parameter to enable callers to avoid
|
||||
* having to declare the exception
|
||||
*/
|
||||
private static <E extends Exception> long computeSizeUTF8_UTF16(byte[] val, Class<E> exClass) throws E {
|
||||
private static <E extends Exception> int encodedLengthUTF8_UTF16(byte[] val, Class<E> 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}}
|
||||
*
|
||||
* <p>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) {
|
||||
|
||||
@ -30,35 +30,35 @@
|
||||
<body>
|
||||
<h1 id="ValueBased">{@index "Value-based Classes"}</h1>
|
||||
|
||||
Some classes, such as <code>java.lang.Integer</code> and
|
||||
<code>java.time.LocalDate</code>, are <em>value-based</em>.
|
||||
Some classes, such as {@code java.lang.Integer} and
|
||||
{@code java.time.LocalDate}, are <em>value-based</em>.
|
||||
A value-based class has the following properties:
|
||||
<ul>
|
||||
<li>the class declares only final instance fields (though these may contain references
|
||||
to mutable objects);</li>
|
||||
<li>the class's implementations of <code>equals</code>, <code>hashCode</code>,
|
||||
and <code>toString</code> compute their results solely from the values
|
||||
<li>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;</li>
|
||||
<li>the class's methods treat instances as <em>freely substitutable</em>
|
||||
when equal, meaning that interchanging any two instances <code>x</code> and
|
||||
<code>y</code> that are equal according to <code>equals()</code> 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;</li>
|
||||
<li>the class performs no synchronization using an instance's monitor;</li>
|
||||
<li>the class does not declare (or has deprecated any) accessible constructors;</li>
|
||||
<li>the class does not declare (or discourages use of) accessible constructors;</li>
|
||||
<li>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 <code>equals()</code>, they may also be
|
||||
equal according to <code>==</code>;</li>
|
||||
<li>the class is final, and extends either <code>Object</code> or a hierarchy of
|
||||
instances are equal according to {@code equals()}, they may also be
|
||||
equal according to {@code ==};</li>
|
||||
<li>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.</li>
|
||||
</ul>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>Synchronization on instances of value-based classes is strongly discouraged,
|
||||
|
||||
@ -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 = "<init>"; // the ever-popular
|
||||
static final String CONSTRUCTOR_NAME = "<init>";
|
||||
|
||||
// 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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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__");
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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).
|
||||
*
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
@ -352,33 +352,15 @@ getPlatformTimeZoneID()
|
||||
}
|
||||
|
||||
static char *
|
||||
mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
|
||||
getJavaTimezoneFromPlatform(const char *tz_buf, size_t tz_len, const char *mapfilename) {
|
||||
FILE *tzmapf;
|
||||
char mapfilename[PATH_MAX + 1];
|
||||
char line[256];
|
||||
int linecount = 0;
|
||||
char *tz_buf = NULL;
|
||||
char *temp_tz = NULL;
|
||||
char *javatz = NULL;
|
||||
size_t tz_len = 0;
|
||||
|
||||
/* On AIX, the TZ environment variable may end with a comma
|
||||
* followed by modifier fields until early AIX6.1.
|
||||
* This restriction has been removed from AIX7. */
|
||||
|
||||
tz_buf = strdup(tz);
|
||||
tz_len = strlen(tz_buf);
|
||||
|
||||
/* Open tzmappings file, with buffer overrun check */
|
||||
if ((strlen(java_home_dir) + 15) > PATH_MAX) {
|
||||
jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir);
|
||||
goto tzerr;
|
||||
}
|
||||
strcpy(mapfilename, java_home_dir);
|
||||
strcat(mapfilename, "/lib/tzmappings");
|
||||
if ((tzmapf = fopen(mapfilename, "r")) == NULL) {
|
||||
jio_fprintf(stderr, "can't open %s\n", mapfilename);
|
||||
goto tzerr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), tzmapf) != NULL) {
|
||||
@ -431,10 +413,50 @@ mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(void) fclose(tzmapf);
|
||||
return javatz;
|
||||
}
|
||||
|
||||
static char *
|
||||
mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
|
||||
char mapfilename[PATH_MAX + 1];
|
||||
char *tz_buf = NULL;
|
||||
char *javatz = NULL;
|
||||
char *temp_tz = NULL;
|
||||
size_t tz_len = 0;
|
||||
|
||||
/* On AIX, the TZ environment variable may end with a comma
|
||||
* followed by modifier fields until early AIX6.1.
|
||||
* This restriction has been removed from AIX7. */
|
||||
|
||||
tz_buf = strdup(tz);
|
||||
tz_len = strlen(tz_buf);
|
||||
|
||||
/* Open tzmappings file, with buffer overrun check */
|
||||
if ((strlen(java_home_dir) + 15) > PATH_MAX) {
|
||||
jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir);
|
||||
goto tzerr;
|
||||
}
|
||||
strcpy(mapfilename, java_home_dir);
|
||||
strcat(mapfilename, "/lib/tzmappings");
|
||||
|
||||
// First attempt to find the Java timezone for the full tz string
|
||||
javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename);
|
||||
|
||||
// If no match was found, check for timezone with truncated value
|
||||
if (javatz == NULL) {
|
||||
temp_tz = strchr(tz, ',');
|
||||
tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz;
|
||||
free((void *) tz_buf);
|
||||
tz_buf = (char *)malloc(tz_len + 1);
|
||||
memcpy(tz_buf, tz, tz_len);
|
||||
tz_buf[tz_len] = '\0';
|
||||
javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename);
|
||||
}
|
||||
|
||||
tzerr:
|
||||
if (tz_buf != NULL ) {
|
||||
if (tz_buf != NULL) {
|
||||
free((void *) tz_buf);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2024, 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
|
||||
@ -101,28 +101,29 @@ import javax.lang.model.SourceVersion;
|
||||
* supports, possibly an empty set.
|
||||
*
|
||||
* For a given round, the tool computes the set of annotation
|
||||
* interfaces that are present on the elements enclosed within the
|
||||
* root elements. If there is at least one annotation interface
|
||||
* present, then as processors claim annotation interfaces, they are
|
||||
* removed from the set of unmatched annotation interfaces. When the
|
||||
* set is empty or no more processors are available, the round has run
|
||||
* to completion. If there are no annotation interfaces present,
|
||||
* annotation processing still occurs but only <i>universal
|
||||
* interfaces that are present on the elements {@linkplain
|
||||
* RoundEnvironment#getElementsAnnotatedWith(TypeElement) included}
|
||||
* within the root elements. If there is at least one annotation
|
||||
* interface present, then as processors claim annotation interfaces,
|
||||
* they are removed from the set of unmatched annotation interfaces.
|
||||
* When the set is empty or no more processors are available, the
|
||||
* round has run to completion. If there are no annotation interfaces
|
||||
* present, annotation processing still occurs but only <i>universal
|
||||
* processors</i> which support processing all annotation interfaces,
|
||||
* {@code "*"}, can claim the (empty) set of annotation interfaces.
|
||||
*
|
||||
* <p>An annotation interface is considered present if there is at least
|
||||
* one annotation of that interface present on an element enclosed within
|
||||
* one annotation of that interface present on an element included within
|
||||
* the root elements of a round. For this purpose, a type parameter is
|
||||
* considered to be enclosed by its {@linkplain
|
||||
* considered to be included by its {@linkplain
|
||||
* TypeParameterElement#getGenericElement generic
|
||||
* element}.
|
||||
|
||||
* For this purpose, a package element is <em>not</em> considered to
|
||||
* enclose the top-level classes and interfaces within that
|
||||
* include the top-level classes and interfaces within that
|
||||
* package. (A root element representing a package is created when a
|
||||
* {@code package-info} file is processed.) Likewise, for this
|
||||
* purpose, a module element is <em>not</em> considered to enclose the
|
||||
* purpose, a module element is <em>not</em> considered to include the
|
||||
* packages within that module. (A root element representing a module
|
||||
* is created when a {@code module-info} file is processed.)
|
||||
*
|
||||
|
||||
@ -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
|
||||
@ -554,22 +554,9 @@ public abstract class AWTEvent extends EventObject {
|
||||
*/
|
||||
void copyPrivateDataInto(AWTEvent that) {
|
||||
that.bdata = this.bdata;
|
||||
// Copy canAccessSystemClipboard value from this into that.
|
||||
if (this instanceof InputEvent && that instanceof InputEvent) {
|
||||
|
||||
AWTAccessor.InputEventAccessor accessor
|
||||
= AWTAccessor.getInputEventAccessor();
|
||||
|
||||
boolean b = accessor.canAccessSystemClipboard((InputEvent) this);
|
||||
accessor.setCanAccessSystemClipboard((InputEvent) that, b);
|
||||
}
|
||||
that.isSystemGenerated = this.isSystemGenerated;
|
||||
}
|
||||
|
||||
void dispatched() {
|
||||
if (this instanceof InputEvent) {
|
||||
AWTAccessor.getInputEventAccessor().
|
||||
setCanAccessSystemClipboard((InputEvent) this, false);
|
||||
}
|
||||
}
|
||||
} // class AWTEvent
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2024, 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
|
||||
@ -309,13 +309,6 @@ public abstract sealed class InputEvent extends ComponentEvent
|
||||
*/
|
||||
int modifiers;
|
||||
|
||||
/*
|
||||
* A flag that indicates that this instance can be used to access
|
||||
* the system clipboard.
|
||||
* This should be false in a headless environment, true in a headful one.
|
||||
*/
|
||||
private transient boolean canAccessSystemClipboard;
|
||||
|
||||
static {
|
||||
/* ensure that the necessary native libraries are loaded */
|
||||
NativeLibLoader.loadLibraries();
|
||||
@ -328,15 +321,6 @@ public abstract sealed class InputEvent extends ComponentEvent
|
||||
return InputEvent.getButtonDownMasks();
|
||||
}
|
||||
|
||||
public boolean canAccessSystemClipboard(InputEvent event) {
|
||||
return event.canAccessSystemClipboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCanAccessSystemClipboard(InputEvent event,
|
||||
boolean canAccessSystemClipboard) {
|
||||
event.canAccessSystemClipboard = canAccessSystemClipboard;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -381,11 +365,6 @@ public abstract sealed class InputEvent extends ComponentEvent
|
||||
super(source, id);
|
||||
this.when = when;
|
||||
this.modifiers = modifiers;
|
||||
canAccessSystemClipboard = canAccessSystemClipboard();
|
||||
}
|
||||
|
||||
private boolean canAccessSystemClipboard() {
|
||||
return !GraphicsEnvironment.isHeadless();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -361,13 +361,6 @@ public final class AWTAccessor {
|
||||
* Accessor for InputEvent.getButtonDownMasks()
|
||||
*/
|
||||
int[] getButtonDownMasks();
|
||||
|
||||
/*
|
||||
* Accessor for InputEvent.canAccessSystemClipboard field
|
||||
*/
|
||||
boolean canAccessSystemClipboard(InputEvent event);
|
||||
void setCanAccessSystemClipboard(InputEvent event,
|
||||
boolean canAccessSystemClipboard);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
## The FreeType Project: Freetype v2.14.1
|
||||
## The FreeType Project: Freetype v2.14.2
|
||||
|
||||
|
||||
### FreeType Notice
|
||||
|
||||
@ -759,7 +759,13 @@ FT_BEGIN_HEADER
|
||||
/**************************************************************************
|
||||
*
|
||||
* Define `TT_CONFIG_OPTION_BDF` if you want to include support for an
|
||||
* embedded 'BDF~' table within SFNT-based bitmap formats.
|
||||
* embedded 'BDF~' table within an SFNT-based `.otb` font file. This table
|
||||
* is an extension used by X11 to preserve BDF properties after conversion
|
||||
* to SFNT containers. See
|
||||
*
|
||||
* https://fontforge.org/docs/techref/non-standard.html#non-standard-bdf
|
||||
*
|
||||
* for more details.
|
||||
*/
|
||||
/* #define TT_CONFIG_OPTION_BDF */
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
* This is the only necessary change, so it is defined here instead
|
||||
* providing a new configuration file.
|
||||
*/
|
||||
#ifdef FT_MACINTOSH
|
||||
#if defined( __APPLE__ ) || ( defined( __MWERKS__ ) && defined( macintosh ) )
|
||||
/* No Carbon frameworks for 64bit 10.4.x. */
|
||||
/* `AvailabilityMacros.h` is available since Mac OS X 10.2, */
|
||||
@ -36,6 +37,7 @@
|
||||
( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 )
|
||||
#undef FT_MACINTOSH
|
||||
#endif
|
||||
#endif /* __APPLE__ ... */
|
||||
|
||||
#elif defined( __SC__ ) || defined( __MRC__ )
|
||||
/* Classic MacOS compilers */
|
||||
|
||||
@ -4318,14 +4318,13 @@ FT_BEGIN_HEADER
|
||||
* property `no-stem-darkening` provided by the 'autofit', 'cff',
|
||||
* 'type1', and 't1cid' modules; see @no-stem-darkening).
|
||||
*
|
||||
* * @FT_PARAM_TAG_LCD_FILTER_WEIGHTS (LCD filter weights, corresponding
|
||||
* to function @FT_Library_SetLcdFilterWeights).
|
||||
*
|
||||
* * @FT_PARAM_TAG_RANDOM_SEED (seed value for the CFF, Type~1, and CID
|
||||
* 'random' operator, corresponding to the `random-seed` property
|
||||
* provided by the 'cff', 'type1', and 't1cid' modules; see
|
||||
* @random-seed).
|
||||
*
|
||||
* * @FT_PARAM_TAG_LCD_FILTER_WEIGHTS (no longer supported).
|
||||
*
|
||||
* Pass `NULL` as `data` in @FT_Parameter for a given tag to reset the
|
||||
* option and use the library or module default again.
|
||||
*
|
||||
@ -4352,25 +4351,17 @@ FT_BEGIN_HEADER
|
||||
* FT_Bool darken_stems = 1;
|
||||
*
|
||||
* FT_Parameter property2;
|
||||
* FT_LcdFiveTapFilter custom_weight =
|
||||
* { 0x11, 0x44, 0x56, 0x44, 0x11 };
|
||||
*
|
||||
* FT_Parameter property3;
|
||||
* FT_Int32 random_seed = 314159265;
|
||||
*
|
||||
* FT_Parameter properties[3] = { property1,
|
||||
* property2,
|
||||
* property3 };
|
||||
* FT_Parameter properties[2] = { property1,
|
||||
* property2 };
|
||||
*
|
||||
*
|
||||
* property1.tag = FT_PARAM_TAG_STEM_DARKENING;
|
||||
* property1.data = &darken_stems;
|
||||
*
|
||||
* property2.tag = FT_PARAM_TAG_LCD_FILTER_WEIGHTS;
|
||||
* property2.data = custom_weight;
|
||||
*
|
||||
* property3.tag = FT_PARAM_TAG_RANDOM_SEED;
|
||||
* property3.data = &random_seed;
|
||||
* property2.tag = FT_PARAM_TAG_RANDOM_SEED;
|
||||
* property2.data = &random_seed;
|
||||
*
|
||||
* FT_Face_Properties( face, 3, properties );
|
||||
* ```
|
||||
@ -4381,7 +4372,7 @@ FT_BEGIN_HEADER
|
||||
* FT_Parameter property;
|
||||
*
|
||||
*
|
||||
* property.tag = FT_PARAM_TAG_LCD_FILTER_WEIGHTS;
|
||||
* property.tag = FT_PARAM_TAG_STEM_DARKENING;
|
||||
* property.data = NULL;
|
||||
*
|
||||
* FT_Face_Properties( face, 1, &property );
|
||||
@ -5178,7 +5169,7 @@ FT_BEGIN_HEADER
|
||||
*/
|
||||
#define FREETYPE_MAJOR 2
|
||||
#define FREETYPE_MINOR 14
|
||||
#define FREETYPE_PATCH 1
|
||||
#define FREETYPE_PATCH 2
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
|
||||
@ -44,7 +44,8 @@ FT_BEGIN_HEADER
|
||||
*
|
||||
* @description:
|
||||
* This section contains the declaration of functions specific to BDF and
|
||||
* PCF fonts.
|
||||
* PCF fonts. They also work for SFNT bitmap fonts that contain a 'BDF~'
|
||||
* table like X11's `.otb` fonts.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -151,7 +152,9 @@ FT_BEGIN_HEADER
|
||||
* FreeType error code. 0~means success.
|
||||
*
|
||||
* @note:
|
||||
* This function only works with BDF faces, returning an error otherwise.
|
||||
* This function only works with BDF faces and SFNT fonts that have a
|
||||
* 'BDF~' table, returning an error otherwise. For the latter, a bitmap
|
||||
* strike size must be selected first.
|
||||
*/
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Get_BDF_Charset_ID( FT_Face face,
|
||||
@ -165,7 +168,7 @@ FT_BEGIN_HEADER
|
||||
* FT_Get_BDF_Property
|
||||
*
|
||||
* @description:
|
||||
* Retrieve a BDF property from a BDF or PCF font file.
|
||||
* Retrieve a BDF property from a BDF or PCF font.
|
||||
*
|
||||
* @input:
|
||||
* face ::
|
||||
@ -196,6 +199,9 @@ FT_BEGIN_HEADER
|
||||
*
|
||||
* In case of error, `aproperty->type` is always set to
|
||||
* @BDF_PROPERTY_TYPE_NONE.
|
||||
*
|
||||
* This also works with SFNT fonts that have a 'BDF~' table, after a
|
||||
* bitmap strike size has been selected.
|
||||
*/
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Get_BDF_Property( FT_Face face,
|
||||
|
||||
@ -875,7 +875,7 @@ FT_BEGIN_HEADER
|
||||
*/
|
||||
typedef struct FT_Span_
|
||||
{
|
||||
short x;
|
||||
unsigned short x;
|
||||
unsigned short len;
|
||||
unsigned char coverage;
|
||||
|
||||
|
||||
@ -145,16 +145,10 @@ FT_BEGIN_HEADER
|
||||
*
|
||||
* FT_LCD_FILTER_LEGACY ::
|
||||
* FT_LCD_FILTER_LEGACY1 ::
|
||||
* This filter corresponds to the original libXft color filter. It
|
||||
* provides high contrast output but can exhibit really bad color
|
||||
* fringes if glyphs are not extremely well hinted to the pixel grid.
|
||||
* This filter is only provided for comparison purposes, and might be
|
||||
* disabled or stay unsupported in the future. The second value is
|
||||
* provided for compatibility with FontConfig, which historically used
|
||||
* different enumeration, sometimes incorrectly forwarded to FreeType.
|
||||
* The legacy libXft color filter is no longer supported and ignored.
|
||||
*
|
||||
* @since:
|
||||
* 2.3.0 (`FT_LCD_FILTER_LEGACY1` since 2.6.2)
|
||||
* 2.3.0
|
||||
*/
|
||||
typedef enum FT_LcdFilter_
|
||||
{
|
||||
|
||||
@ -133,11 +133,8 @@ FT_BEGIN_HEADER
|
||||
* FT_PARAM_TAG_LCD_FILTER_WEIGHTS
|
||||
*
|
||||
* @description:
|
||||
* An @FT_Parameter tag to be used with @FT_Face_Properties. The
|
||||
* corresponding argument specifies the five LCD filter weights for a
|
||||
* given face (if using @FT_LOAD_TARGET_LCD, for example), overriding the
|
||||
* global default values or the values set up with
|
||||
* @FT_Library_SetLcdFilterWeights.
|
||||
* Overriding global LCD filter weights with custom values for a given
|
||||
* face is no longer supported and ignored.
|
||||
*
|
||||
* @since:
|
||||
* 2.8
|
||||
|
||||
@ -191,8 +191,8 @@ FT_BEGIN_HEADER
|
||||
FT_UInt weight;
|
||||
FT_Bool is_fixed_pitch;
|
||||
FT_Fixed italic_angle;
|
||||
FT_Fixed underline_position;
|
||||
FT_Fixed underline_thickness;
|
||||
FT_Short underline_position;
|
||||
FT_UShort underline_thickness;
|
||||
FT_Int paint_type;
|
||||
FT_Int charstring_type;
|
||||
FT_Matrix font_matrix;
|
||||
|
||||
@ -365,11 +365,6 @@ FT_BEGIN_HEADER
|
||||
* Value~0 means to use the font's value. Value~-1 means to use the
|
||||
* CFF driver's default.
|
||||
*
|
||||
* lcd_weights ::
|
||||
* lcd_filter_func ::
|
||||
* These fields specify the LCD filtering weights and callback function
|
||||
* for ClearType-style subpixel rendering.
|
||||
*
|
||||
* refcount ::
|
||||
* A counter initialized to~1 at the time an @FT_Face structure is
|
||||
* created. @FT_Reference_Face increments this counter, and
|
||||
@ -391,11 +386,6 @@ FT_BEGIN_HEADER
|
||||
FT_Char no_stem_darkening;
|
||||
FT_Int32 random_seed;
|
||||
|
||||
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
||||
FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */
|
||||
FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */
|
||||
#endif
|
||||
|
||||
FT_Int refcount;
|
||||
|
||||
} FT_Face_InternalRec;
|
||||
@ -724,9 +714,9 @@ FT_BEGIN_HEADER
|
||||
const FT_Vector* origin );
|
||||
|
||||
/* Allocate a new bitmap buffer in a glyph slot. */
|
||||
/* Dimensions must be preset in advance. */
|
||||
FT_BASE( FT_Error )
|
||||
ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot,
|
||||
FT_ULong size );
|
||||
ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot );
|
||||
|
||||
|
||||
/* Set the bitmap buffer in a glyph slot to a given pointer. The buffer */
|
||||
@ -889,10 +879,6 @@ FT_BEGIN_HEADER
|
||||
* lcd_weights ::
|
||||
* The LCD filter weights for ClearType-style subpixel rendering.
|
||||
*
|
||||
* lcd_filter_func ::
|
||||
* The LCD filtering callback function for for ClearType-style subpixel
|
||||
* rendering.
|
||||
*
|
||||
* lcd_geometry ::
|
||||
* This array specifies LCD subpixel geometry and controls Harmony LCD
|
||||
* rendering technique, alternative to ClearType.
|
||||
@ -926,7 +912,6 @@ FT_BEGIN_HEADER
|
||||
|
||||
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
||||
FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */
|
||||
FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */
|
||||
#else
|
||||
FT_Vector lcd_geometry[3]; /* RGB subpixel positions */
|
||||
#endif
|
||||
@ -995,17 +980,6 @@ FT_BEGIN_HEADER
|
||||
#endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */
|
||||
|
||||
|
||||
/* Define default raster's interface. The default raster is located in */
|
||||
/* `src/base/ftraster.c'. */
|
||||
/* */
|
||||
/* Client applications can register new rasters through the */
|
||||
/* FT_Set_Raster() API. */
|
||||
|
||||
#ifndef FT_NO_DEFAULT_RASTER
|
||||
FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster;
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
|
||||
@ -92,7 +92,7 @@ FT_BEGIN_HEADER
|
||||
FT_String* full_name;
|
||||
FT_String* family_name;
|
||||
FT_String* weight;
|
||||
FT_Long italic_angle;
|
||||
FT_Fixed italic_angle;
|
||||
FT_Bool is_fixed_pitch;
|
||||
FT_Short underline_position;
|
||||
FT_UShort underline_thickness;
|
||||
@ -645,7 +645,7 @@ FT_BEGIN_HEADER
|
||||
PS_DICT_UNDERLINE_POSITION, /* FT_Short */
|
||||
PS_DICT_UNDERLINE_THICKNESS, /* FT_UShort */
|
||||
PS_DICT_FS_TYPE, /* FT_UShort */
|
||||
PS_DICT_ITALIC_ANGLE, /* FT_Long */
|
||||
PS_DICT_ITALIC_ANGLE, /* FT_Fixed */
|
||||
|
||||
PS_DICT_MAX = PS_DICT_ITALIC_ANGLE
|
||||
|
||||
|
||||
@ -1405,7 +1405,8 @@
|
||||
FT_TRACE4(( " " ));
|
||||
idx = HB_SET_VALUE_INVALID;
|
||||
while ( hb( set_next )( gsub_lookups, &idx ) )
|
||||
if ( globals->gsub_lookups_single_alternate[idx] )
|
||||
if ( idx < globals->gsub_lookup_count &&
|
||||
globals->gsub_lookups_single_alternate[idx] )
|
||||
{
|
||||
have_idx = TRUE;
|
||||
FT_TRACE4(( " %u", idx ));
|
||||
@ -1428,9 +1429,17 @@
|
||||
idx = HB_SET_VALUE_INVALID;
|
||||
while ( hb( set_next )( gsub_lookups, &idx ) )
|
||||
{
|
||||
FT_UInt32 offset = globals->gsub_lookups_single_alternate[idx];
|
||||
FT_UInt32 offset;
|
||||
|
||||
|
||||
/* HarfBuzz only validates lookup indices while */
|
||||
/* processing lookups, not while collecting them, */
|
||||
/* so we have to do that by ourselves. */
|
||||
if ( idx < globals->gsub_lookup_count )
|
||||
offset = globals->gsub_lookups_single_alternate[idx];
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
/* 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 */
|
||||
|
||||
@ -116,7 +116,9 @@ FT_BEGIN_HEADER
|
||||
|
||||
/* The GSUB table. */
|
||||
FT_Byte* gsub;
|
||||
/* Lookup offsets, with only SingleSubst and AlternateSubst non-NULL. */
|
||||
/* An array of lookup offsets (of `gsub_lookup_count` elements), */
|
||||
/* with only SingleSubst and AlternateSubst lookups non-NULL. */
|
||||
FT_UShort gsub_lookup_count;
|
||||
FT_UInt32* gsub_lookups_single_alternate;
|
||||
#endif
|
||||
|
||||
|
||||
@ -3269,9 +3269,9 @@
|
||||
next_on = next_on->next;
|
||||
|
||||
if ( next_on->y > p->y && prev_on->y > p->y )
|
||||
measurement = p->y - min_y;
|
||||
measurement = SUB_LONG( p->y, min_y );
|
||||
else if ( next_on->y < p->y && prev_on->y < p->y )
|
||||
measurement = max_y - p->y;
|
||||
measurement = SUB_LONG( max_y, p->y );
|
||||
else
|
||||
continue;
|
||||
|
||||
@ -3309,11 +3309,14 @@
|
||||
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;
|
||||
p = p->next;
|
||||
/* We adjust the height of the diacritic only, which means */
|
||||
/* we are never dealing with (valid) large numbers and can */
|
||||
/* thus avoid `FT_MulFix`. */
|
||||
p->y = ADD_LONG( MUL_LONG( SUB_LONG( p->y,
|
||||
min_y ),
|
||||
target_height ) / height,
|
||||
min_y );
|
||||
|
||||
} while ( p != first_point );
|
||||
|
||||
@ -3370,9 +3373,9 @@
|
||||
next_on = next_on->next;
|
||||
|
||||
if ( next_on->y > p->y && prev_on->y > p->y )
|
||||
measurement = p->y - min_y;
|
||||
measurement = SUB_LONG( p->y, min_y );
|
||||
else if ( next_on->y < p->y && prev_on->y < p->y )
|
||||
measurement = max_y - p->y;
|
||||
measurement = SUB_LONG( max_y, p->y );
|
||||
else
|
||||
continue;
|
||||
|
||||
@ -3403,8 +3406,11 @@
|
||||
p = first_point;
|
||||
do
|
||||
{
|
||||
p = p->next;
|
||||
p->y = ( ( p->y - max_y ) * target_height / height ) + max_y;
|
||||
p = p->next;
|
||||
p->y = ADD_LONG( MUL_LONG( SUB_LONG( p->y,
|
||||
max_y ),
|
||||
target_height ) / height,
|
||||
max_y );
|
||||
|
||||
} while ( p != first_point );
|
||||
|
||||
@ -3462,9 +3468,9 @@
|
||||
} 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;
|
||||
min_y_rounded = FT_PIX_ROUND_LONG( min_y );
|
||||
delta = SUB_LONG( min_y_rounded, min_y );
|
||||
height = SUB_LONG( 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. */
|
||||
@ -3502,9 +3508,9 @@
|
||||
|
||||
} while ( p != first_point );
|
||||
|
||||
max_y_rounded = FT_PIX_ROUND( max_y );
|
||||
delta = max_y_rounded - max_y;
|
||||
height = max_y - min_y;
|
||||
max_y_rounded = FT_PIX_ROUND_LONG( max_y );
|
||||
delta = SUB_LONG( max_y_rounded, max_y );
|
||||
height = SUB_LONG( max_y, min_y );
|
||||
|
||||
if ( height < 64 * 3 )
|
||||
delta -= ( FT_PIX_ROUND( height ) - height ) / 2;
|
||||
@ -3673,7 +3679,7 @@
|
||||
|
||||
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;
|
||||
high_height = SUB_LONG( high_max_y, high_min_y );
|
||||
|
||||
if ( high_height > accent_height_limit )
|
||||
{
|
||||
@ -3705,7 +3711,7 @@
|
||||
/* 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;
|
||||
distance = SUB_LONG( high_min_y, max_y );
|
||||
if ( distance < 64 &&
|
||||
distance < min_distance &&
|
||||
min_y < high_min_y )
|
||||
@ -3724,14 +3730,14 @@
|
||||
|
||||
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;
|
||||
tilde_height = SUB_LONG( 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;
|
||||
pos = ADD_LONG( high_min_y, adjustment_amount );
|
||||
if ( adjust_below_top && is_top_tilde )
|
||||
pos += high_height;
|
||||
|
||||
@ -3764,7 +3770,7 @@
|
||||
{
|
||||
/* Value 8 is heuristic. */
|
||||
FT_Pos height_delta = high_height / 8;
|
||||
FT_Pos min_y_limit = high_min_y - height_delta;
|
||||
FT_Pos min_y_limit = SUB_LONG( high_min_y, height_delta );
|
||||
|
||||
|
||||
FT_TRACE4(( " Pushing high contour %ld units up\n",
|
||||
@ -3784,7 +3790,7 @@
|
||||
centering_adjustment ));
|
||||
|
||||
af_move_contours_up( hints,
|
||||
min_y_limit + high_height,
|
||||
ADD_LONG( min_y_limit, high_height ),
|
||||
centering_adjustment );
|
||||
}
|
||||
}
|
||||
@ -3838,7 +3844,7 @@
|
||||
|
||||
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;
|
||||
low_height = SUB_LONG( low_max_y, low_min_y );
|
||||
|
||||
if ( low_height > accent_height_limit )
|
||||
{
|
||||
@ -3863,7 +3869,7 @@
|
||||
min_y = hints->contour_y_minima[contour];
|
||||
max_y = hints->contour_y_maxima[contour];
|
||||
|
||||
distance = min_y - low_max_y;
|
||||
distance = SUB_LONG( min_y, low_max_y );
|
||||
if ( distance < 64 &&
|
||||
distance < min_distance &&
|
||||
max_y > low_max_y )
|
||||
@ -3882,9 +3888,9 @@
|
||||
|
||||
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;
|
||||
tilde_height = SUB_LONG( tilde_max_y, tilde_min_y );
|
||||
|
||||
pos = low_max_y - adjustment_amount;
|
||||
pos = SUB_LONG( low_max_y, adjustment_amount );
|
||||
if ( adjust_above_bottom && is_bottom_tilde )
|
||||
pos -= low_height;
|
||||
|
||||
@ -3915,7 +3921,7 @@
|
||||
( calculated_amount <= 66 || adjustment_amount <= 66 ) )
|
||||
{
|
||||
FT_Pos height_delta = low_height / 8;
|
||||
FT_Pos max_y_limit = low_max_y + height_delta;
|
||||
FT_Pos max_y_limit = ADD_LONG( low_max_y, height_delta );
|
||||
|
||||
|
||||
FT_TRACE4(( " Pushing low contour %ld units down\n",
|
||||
@ -3929,7 +3935,7 @@
|
||||
centering_adjustment ));
|
||||
|
||||
af_move_contours_down( hints,
|
||||
max_y_limit - low_height,
|
||||
SUB_LONG( max_y_limit, low_height ),
|
||||
centering_adjustment );
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,16 +524,18 @@
|
||||
|
||||
bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
|
||||
bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
|
||||
bbox.xMax = FT_PIX_CEIL( bbox.xMax );
|
||||
bbox.yMax = FT_PIX_CEIL( bbox.yMax );
|
||||
bbox.xMax = FT_PIX_CEIL_LONG( bbox.xMax );
|
||||
bbox.yMax = FT_PIX_CEIL_LONG( bbox.yMax );
|
||||
|
||||
slot->metrics.width = bbox.xMax - bbox.xMin;
|
||||
slot->metrics.height = bbox.yMax - bbox.yMin;
|
||||
slot->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin );
|
||||
slot->metrics.height = SUB_LONG( bbox.yMax, bbox.yMin );
|
||||
slot->metrics.horiBearingX = bbox.xMin;
|
||||
slot->metrics.horiBearingY = bbox.yMax;
|
||||
|
||||
slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
|
||||
slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
|
||||
slot->metrics.vertBearingX = FT_PIX_FLOOR( ADD_LONG( bbox.xMin,
|
||||
vvector.x ) );
|
||||
slot->metrics.vertBearingY = FT_PIX_FLOOR( ADD_LONG( bbox.yMax,
|
||||
vvector.y ) );
|
||||
|
||||
/* for mono-width fonts (like Andale, Courier, etc.) we need */
|
||||
/* to keep the original rounded advance width; ditto for */
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
#include <freetype/ftadvanc.h>
|
||||
#include <freetype/internal/ftobjs.h>
|
||||
#include <freetype/internal/ftcalc.h>
|
||||
|
||||
|
||||
static FT_Error
|
||||
@ -47,11 +48,43 @@
|
||||
/* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c) */
|
||||
|
||||
for ( nn = 0; nn < count; nn++ )
|
||||
advances[nn] = FT_MulDiv( advances[nn], scale, 64 );
|
||||
advances[nn] = FT_MulFix( 1024 * advances[nn], scale );
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
/* loading (and hinting) to calculate the advances is slow */
|
||||
/* unless TrueType hdmx table is provided as an accelerator */
|
||||
static FT_Error
|
||||
ft_load_advances( FT_Face face,
|
||||
FT_UInt gindex,
|
||||
FT_UInt count,
|
||||
FT_Int32 flags,
|
||||
FT_Fixed *padvances )
|
||||
{
|
||||
FT_UInt nn;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_Pos factor = flags & FT_LOAD_NO_SCALE ? 1 : 1024;
|
||||
FT_Pos* advance = flags & FT_LOAD_VERTICAL_LAYOUT
|
||||
? &face->glyph->advance.y
|
||||
: &face->glyph->advance.x;
|
||||
|
||||
|
||||
flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
|
||||
|
||||
for ( nn = 0; nn < count; nn++ )
|
||||
{
|
||||
error = FT_Load_Glyph( face, gindex + nn, flags );
|
||||
if ( error )
|
||||
break;
|
||||
|
||||
/* scale from 26.6 to 16.16, unless NO_SCALE was requested */
|
||||
padvances[nn] = *advance * factor;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* at the moment, we can perform fast advance retrieval only in */
|
||||
/* the following cases: */
|
||||
@ -102,7 +135,10 @@
|
||||
return error;
|
||||
}
|
||||
|
||||
return FT_Get_Advances( face, gindex, 1, flags, padvance );
|
||||
if ( flags & FT_ADVANCE_FLAG_FAST_ONLY )
|
||||
return FT_THROW( Unimplemented_Feature );
|
||||
|
||||
return ft_load_advances( face, gindex, 1, flags, padvance );
|
||||
}
|
||||
|
||||
|
||||
@ -115,12 +151,9 @@
|
||||
FT_Int32 flags,
|
||||
FT_Fixed *padvances )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
||||
FT_Face_GetAdvancesFunc func;
|
||||
|
||||
FT_UInt num, end, nn;
|
||||
FT_Int factor;
|
||||
FT_UInt num, end;
|
||||
|
||||
|
||||
if ( !face )
|
||||
@ -140,6 +173,9 @@
|
||||
func = face->driver->clazz->get_advances;
|
||||
if ( func && LOAD_ADVANCE_FAST_CHECK( face, flags ) )
|
||||
{
|
||||
FT_Error error;
|
||||
|
||||
|
||||
error = func( face, start, count, flags, padvances );
|
||||
if ( !error )
|
||||
return ft_face_scale_advances_( face, padvances, count, flags );
|
||||
@ -148,26 +184,10 @@
|
||||
return error;
|
||||
}
|
||||
|
||||
error = FT_Err_Ok;
|
||||
|
||||
if ( flags & FT_ADVANCE_FLAG_FAST_ONLY )
|
||||
return FT_THROW( Unimplemented_Feature );
|
||||
|
||||
flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY;
|
||||
factor = ( flags & FT_LOAD_NO_SCALE ) ? 1 : 1024;
|
||||
for ( nn = 0; nn < count; nn++ )
|
||||
{
|
||||
error = FT_Load_Glyph( face, start + nn, flags );
|
||||
if ( error )
|
||||
break;
|
||||
|
||||
/* scale from 26.6 to 16.16, unless NO_SCALE was requested */
|
||||
padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
|
||||
? face->glyph->advance.y * factor
|
||||
: face->glyph->advance.x * factor;
|
||||
}
|
||||
|
||||
return error;
|
||||
return ft_load_advances( face, start, count, flags, padvances );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -922,14 +922,7 @@
|
||||
target->pitch = (int)final_width * 4;
|
||||
target->num_grays = 256;
|
||||
|
||||
if ( FT_LONG_MAX / target->pitch < (int)target->rows )
|
||||
{
|
||||
FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%u x %u)\n",
|
||||
final_width, final_rows ));
|
||||
return FT_THROW( Invalid_Argument );
|
||||
}
|
||||
|
||||
if ( FT_ALLOC( target->buffer, target->pitch * (int)target->rows ) )
|
||||
if ( FT_ALLOC_MULT( target->buffer, target->rows, target->pitch ) )
|
||||
return error;
|
||||
|
||||
free_target_bitmap_on_error = 1;
|
||||
@ -950,16 +943,9 @@
|
||||
|
||||
new_pitch = (int)final_width * 4;
|
||||
|
||||
if ( FT_LONG_MAX / new_pitch < (int)final_rows )
|
||||
{
|
||||
FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%u x %u)\n",
|
||||
final_width, final_rows ));
|
||||
return FT_THROW( Invalid_Argument );
|
||||
}
|
||||
|
||||
/* TODO: provide an in-buffer solution for large bitmaps */
|
||||
/* to avoid allocation of a new buffer */
|
||||
if ( FT_ALLOC( buffer, new_pitch * (int)final_rows ) )
|
||||
if ( FT_ALLOC_MULT( buffer, final_rows, new_pitch ) )
|
||||
goto Error;
|
||||
|
||||
/* copy data to new buffer */
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
FT_GlyphSlot slot )
|
||||
{
|
||||
FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_Error error;
|
||||
FT_Library library = FT_GLYPH( glyph )->library;
|
||||
|
||||
|
||||
@ -75,17 +75,8 @@
|
||||
glyph->left = slot->bitmap_left;
|
||||
glyph->top = slot->bitmap_top;
|
||||
|
||||
/* do lazy copying whenever possible */
|
||||
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
|
||||
{
|
||||
glyph->bitmap = slot->bitmap;
|
||||
slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
|
||||
}
|
||||
else
|
||||
{
|
||||
FT_Bitmap_Init( &glyph->bitmap );
|
||||
error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
|
||||
}
|
||||
FT_Bitmap_Init( &glyph->bitmap );
|
||||
error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
|
||||
@ -25,265 +25,28 @@
|
||||
|
||||
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
||||
|
||||
/* define USE_LEGACY to implement the legacy filter */
|
||||
#define USE_LEGACY
|
||||
|
||||
#define FT_SHIFTCLAMP( x ) ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) )
|
||||
|
||||
|
||||
/* add padding according to filter weights */
|
||||
/* add padding sufficient for a 5-tap filter, */
|
||||
/* which is 2/3 of a pixel */
|
||||
FT_BASE_DEF( void )
|
||||
ft_lcd_padding( FT_BBox* cbox,
|
||||
FT_GlyphSlot slot,
|
||||
FT_Render_Mode mode )
|
||||
{
|
||||
FT_Byte* lcd_weights;
|
||||
FT_Bitmap_LcdFilterFunc lcd_filter_func;
|
||||
FT_UNUSED( slot );
|
||||
|
||||
|
||||
/* Per-face LCD filtering takes priority if set up. */
|
||||
if ( slot->face && slot->face->internal->lcd_filter_func )
|
||||
if ( mode == FT_RENDER_MODE_LCD )
|
||||
{
|
||||
lcd_weights = slot->face->internal->lcd_weights;
|
||||
lcd_filter_func = slot->face->internal->lcd_filter_func;
|
||||
cbox->xMin -= 43;
|
||||
cbox->xMax += 43;
|
||||
}
|
||||
else
|
||||
else if ( mode == FT_RENDER_MODE_LCD_V )
|
||||
{
|
||||
lcd_weights = slot->library->lcd_weights;
|
||||
lcd_filter_func = slot->library->lcd_filter_func;
|
||||
}
|
||||
|
||||
if ( lcd_filter_func == ft_lcd_filter_fir )
|
||||
{
|
||||
if ( mode == FT_RENDER_MODE_LCD )
|
||||
{
|
||||
cbox->xMin -= lcd_weights[0] ? 43 :
|
||||
lcd_weights[1] ? 22 : 0;
|
||||
cbox->xMax += lcd_weights[4] ? 43 :
|
||||
lcd_weights[3] ? 22 : 0;
|
||||
}
|
||||
else if ( mode == FT_RENDER_MODE_LCD_V )
|
||||
{
|
||||
cbox->yMin -= lcd_weights[0] ? 43 :
|
||||
lcd_weights[1] ? 22 : 0;
|
||||
cbox->yMax += lcd_weights[4] ? 43 :
|
||||
lcd_weights[3] ? 22 : 0;
|
||||
}
|
||||
cbox->yMin -= 43;
|
||||
cbox->yMax += 43;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* FIR filter used by the default and light filters */
|
||||
FT_BASE_DEF( void )
|
||||
ft_lcd_filter_fir( FT_Bitmap* bitmap,
|
||||
FT_LcdFiveTapFilter weights )
|
||||
{
|
||||
FT_UInt width = (FT_UInt)bitmap->width;
|
||||
FT_UInt height = (FT_UInt)bitmap->rows;
|
||||
FT_Int pitch = bitmap->pitch;
|
||||
FT_Byte* origin = bitmap->buffer;
|
||||
FT_Byte mode = bitmap->pixel_mode;
|
||||
|
||||
|
||||
/* take care of bitmap flow */
|
||||
if ( pitch > 0 && height > 0 )
|
||||
origin += pitch * (FT_Int)( height - 1 );
|
||||
|
||||
/* horizontal in-place FIR filter */
|
||||
if ( mode == FT_PIXEL_MODE_LCD && width >= 2 )
|
||||
{
|
||||
FT_Byte* line = origin;
|
||||
|
||||
|
||||
/* `fir' must be at least 32 bit wide, since the sum of */
|
||||
/* the values in `weights' can exceed 0xFF */
|
||||
|
||||
for ( ; height > 0; height--, line -= pitch )
|
||||
{
|
||||
FT_UInt fir[5];
|
||||
FT_UInt val, xx;
|
||||
|
||||
|
||||
val = line[0];
|
||||
fir[2] = weights[2] * val;
|
||||
fir[3] = weights[3] * val;
|
||||
fir[4] = weights[4] * val;
|
||||
|
||||
val = line[1];
|
||||
fir[1] = fir[2] + weights[1] * val;
|
||||
fir[2] = fir[3] + weights[2] * val;
|
||||
fir[3] = fir[4] + weights[3] * val;
|
||||
fir[4] = weights[4] * val;
|
||||
|
||||
for ( xx = 2; xx < width; xx++ )
|
||||
{
|
||||
val = line[xx];
|
||||
fir[0] = fir[1] + weights[0] * val;
|
||||
fir[1] = fir[2] + weights[1] * val;
|
||||
fir[2] = fir[3] + weights[2] * val;
|
||||
fir[3] = fir[4] + weights[3] * val;
|
||||
fir[4] = weights[4] * val;
|
||||
|
||||
line[xx - 2] = FT_SHIFTCLAMP( fir[0] );
|
||||
}
|
||||
|
||||
line[xx - 2] = FT_SHIFTCLAMP( fir[1] );
|
||||
line[xx - 1] = FT_SHIFTCLAMP( fir[2] );
|
||||
}
|
||||
}
|
||||
|
||||
/* vertical in-place FIR filter */
|
||||
else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 )
|
||||
{
|
||||
FT_Byte* column = origin;
|
||||
|
||||
|
||||
for ( ; width > 0; width--, column++ )
|
||||
{
|
||||
FT_Byte* col = column;
|
||||
FT_UInt fir[5];
|
||||
FT_UInt val, yy;
|
||||
|
||||
|
||||
val = col[0];
|
||||
fir[2] = weights[2] * val;
|
||||
fir[3] = weights[3] * val;
|
||||
fir[4] = weights[4] * val;
|
||||
col -= pitch;
|
||||
|
||||
val = col[0];
|
||||
fir[1] = fir[2] + weights[1] * val;
|
||||
fir[2] = fir[3] + weights[2] * val;
|
||||
fir[3] = fir[4] + weights[3] * val;
|
||||
fir[4] = weights[4] * val;
|
||||
col -= pitch;
|
||||
|
||||
for ( yy = 2; yy < height; yy++, col -= pitch )
|
||||
{
|
||||
val = col[0];
|
||||
fir[0] = fir[1] + weights[0] * val;
|
||||
fir[1] = fir[2] + weights[1] * val;
|
||||
fir[2] = fir[3] + weights[2] * val;
|
||||
fir[3] = fir[4] + weights[3] * val;
|
||||
fir[4] = weights[4] * val;
|
||||
|
||||
col[pitch * 2] = FT_SHIFTCLAMP( fir[0] );
|
||||
}
|
||||
|
||||
col[pitch * 2] = FT_SHIFTCLAMP( fir[1] );
|
||||
col[pitch] = FT_SHIFTCLAMP( fir[2] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_LEGACY
|
||||
|
||||
/* intra-pixel filter used by the legacy filter */
|
||||
static void
|
||||
_ft_lcd_filter_legacy( FT_Bitmap* bitmap,
|
||||
FT_Byte* weights )
|
||||
{
|
||||
FT_UInt width = (FT_UInt)bitmap->width;
|
||||
FT_UInt height = (FT_UInt)bitmap->rows;
|
||||
FT_Int pitch = bitmap->pitch;
|
||||
FT_Byte* origin = bitmap->buffer;
|
||||
FT_Byte mode = bitmap->pixel_mode;
|
||||
|
||||
static const unsigned int filters[3][3] =
|
||||
{
|
||||
{ 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
|
||||
{ 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
|
||||
{ 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
|
||||
};
|
||||
|
||||
FT_UNUSED( weights );
|
||||
|
||||
|
||||
/* take care of bitmap flow */
|
||||
if ( pitch > 0 && height > 0 )
|
||||
origin += pitch * (FT_Int)( height - 1 );
|
||||
|
||||
/* horizontal in-place intra-pixel filter */
|
||||
if ( mode == FT_PIXEL_MODE_LCD && width >= 3 )
|
||||
{
|
||||
FT_Byte* line = origin;
|
||||
|
||||
|
||||
for ( ; height > 0; height--, line -= pitch )
|
||||
{
|
||||
FT_UInt xx;
|
||||
|
||||
|
||||
for ( xx = 0; xx < width; xx += 3 )
|
||||
{
|
||||
FT_UInt r, g, b;
|
||||
FT_UInt p;
|
||||
|
||||
|
||||
p = line[xx];
|
||||
r = filters[0][0] * p;
|
||||
g = filters[0][1] * p;
|
||||
b = filters[0][2] * p;
|
||||
|
||||
p = line[xx + 1];
|
||||
r += filters[1][0] * p;
|
||||
g += filters[1][1] * p;
|
||||
b += filters[1][2] * p;
|
||||
|
||||
p = line[xx + 2];
|
||||
r += filters[2][0] * p;
|
||||
g += filters[2][1] * p;
|
||||
b += filters[2][2] * p;
|
||||
|
||||
line[xx] = (FT_Byte)( r / 65536 );
|
||||
line[xx + 1] = (FT_Byte)( g / 65536 );
|
||||
line[xx + 2] = (FT_Byte)( b / 65536 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 )
|
||||
{
|
||||
FT_Byte* column = origin;
|
||||
|
||||
|
||||
for ( ; width > 0; width--, column++ )
|
||||
{
|
||||
FT_Byte* col = column - 2 * pitch;
|
||||
|
||||
|
||||
for ( ; height > 0; height -= 3, col -= 3 * pitch )
|
||||
{
|
||||
FT_UInt r, g, b;
|
||||
FT_UInt p;
|
||||
|
||||
|
||||
p = col[0];
|
||||
r = filters[0][0] * p;
|
||||
g = filters[0][1] * p;
|
||||
b = filters[0][2] * p;
|
||||
|
||||
p = col[pitch];
|
||||
r += filters[1][0] * p;
|
||||
g += filters[1][1] * p;
|
||||
b += filters[1][2] * p;
|
||||
|
||||
p = col[pitch * 2];
|
||||
r += filters[2][0] * p;
|
||||
g += filters[2][1] * p;
|
||||
b += filters[2][2] * p;
|
||||
|
||||
col[0] = (FT_Byte)( r / 65536 );
|
||||
col[pitch] = (FT_Byte)( g / 65536 );
|
||||
col[pitch * 2] = (FT_Byte)( b / 65536 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_LEGACY */
|
||||
|
||||
|
||||
/* documentation in ftlcdfil.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
@ -297,7 +60,6 @@
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
|
||||
library->lcd_filter_func = ft_lcd_filter_fir;
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
@ -321,32 +83,23 @@
|
||||
switch ( filter )
|
||||
{
|
||||
case FT_LCD_FILTER_NONE:
|
||||
library->lcd_filter_func = NULL;
|
||||
ft_memset( library->lcd_weights,
|
||||
0,
|
||||
FT_LCD_FILTER_FIVE_TAPS );
|
||||
break;
|
||||
|
||||
case FT_LCD_FILTER_DEFAULT:
|
||||
ft_memcpy( library->lcd_weights,
|
||||
default_weights,
|
||||
FT_LCD_FILTER_FIVE_TAPS );
|
||||
library->lcd_filter_func = ft_lcd_filter_fir;
|
||||
break;
|
||||
|
||||
case FT_LCD_FILTER_LIGHT:
|
||||
ft_memcpy( library->lcd_weights,
|
||||
light_weights,
|
||||
FT_LCD_FILTER_FIVE_TAPS );
|
||||
library->lcd_filter_func = ft_lcd_filter_fir;
|
||||
break;
|
||||
|
||||
#ifdef USE_LEGACY
|
||||
|
||||
case FT_LCD_FILTER_LEGACY:
|
||||
case FT_LCD_FILTER_LEGACY1:
|
||||
library->lcd_filter_func = _ft_lcd_filter_legacy;
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
default:
|
||||
return FT_THROW( Invalid_Argument );
|
||||
}
|
||||
|
||||
@ -524,12 +524,28 @@
|
||||
bitmap->rows = (unsigned int)height;
|
||||
bitmap->pitch = pitch;
|
||||
|
||||
if ( pbox.xMin < -0x8000 || pbox.xMax > 0x7FFF ||
|
||||
pbox.yMin < -0x8000 || pbox.yMax > 0x7FFF )
|
||||
/* Flag the bounding box size unsuitable for rendering. */
|
||||
/* FT_Renderer modules should check the return value. */
|
||||
/* The limit is based on the ppem value when available. */
|
||||
{
|
||||
FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n",
|
||||
pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax ));
|
||||
return 1;
|
||||
FT_Face face = slot->face;
|
||||
FT_Pos xlim = 0x8000;
|
||||
FT_Pos ylim = 0x8000;
|
||||
|
||||
|
||||
if ( face )
|
||||
{
|
||||
xlim = FT_MIN( xlim, 10 * face->size->metrics.x_ppem );
|
||||
ylim = FT_MIN( ylim, 10 * face->size->metrics.y_ppem );
|
||||
}
|
||||
|
||||
if ( pbox.xMin < -xlim || pbox.xMax >= xlim ||
|
||||
pbox.yMin < -ylim || pbox.yMax >= ylim )
|
||||
{
|
||||
FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n",
|
||||
pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax ));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -549,8 +565,7 @@
|
||||
|
||||
|
||||
FT_BASE_DEF( FT_Error )
|
||||
ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot,
|
||||
FT_ULong size )
|
||||
ft_glyphslot_alloc_bitmap( FT_GlyphSlot slot )
|
||||
{
|
||||
FT_Memory memory = FT_FACE_MEMORY( slot->face );
|
||||
FT_Error error;
|
||||
@ -561,7 +576,10 @@
|
||||
else
|
||||
slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
|
||||
|
||||
FT_MEM_ALLOC( slot->bitmap.buffer, size );
|
||||
/* dimensions must be preset */
|
||||
FT_MEM_ALLOC_MULT( slot->bitmap.buffer,
|
||||
slot->bitmap.rows,
|
||||
slot->bitmap.pitch );
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1413,7 +1431,10 @@
|
||||
if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT &&
|
||||
cur[0]->encoding_id == TT_MS_ID_UCS_4 ) ||
|
||||
( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
|
||||
cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) )
|
||||
cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ||
|
||||
( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE &&
|
||||
cur[0]->encoding_id == TT_APPLE_ID_FULL_UNICODE &&
|
||||
FT_Get_CMap_Format( cur[0] ) == 13 ) )
|
||||
{
|
||||
face->charmap = cur[0];
|
||||
return FT_Err_Ok;
|
||||
@ -2798,11 +2819,6 @@
|
||||
internal->refcount = 1;
|
||||
|
||||
internal->no_stem_darkening = -1;
|
||||
|
||||
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
||||
/* Per-face filtering can only be set up by FT_Face_Properties */
|
||||
internal->lcd_filter_func = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( aface )
|
||||
@ -4032,18 +4048,8 @@
|
||||
}
|
||||
else if ( properties->tag == FT_PARAM_TAG_LCD_FILTER_WEIGHTS )
|
||||
{
|
||||
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
||||
if ( properties->data )
|
||||
{
|
||||
ft_memcpy( face->internal->lcd_weights,
|
||||
properties->data,
|
||||
FT_LCD_FILTER_FIVE_TAPS );
|
||||
face->internal->lcd_filter_func = ft_lcd_filter_fir;
|
||||
}
|
||||
#else
|
||||
error = FT_THROW( Unimplemented_Feature );
|
||||
goto Exit;
|
||||
#endif
|
||||
}
|
||||
else if ( properties->tag == FT_PARAM_TAG_RANDOM_SEED )
|
||||
{
|
||||
|
||||
@ -424,11 +424,10 @@
|
||||
while ( cur )
|
||||
{
|
||||
FT_ListNode next = cur->next;
|
||||
void* data = cur->data;
|
||||
|
||||
|
||||
if ( destroy )
|
||||
destroy( memory, data, user );
|
||||
destroy( memory, cur->data, user );
|
||||
|
||||
FT_FREE( cur );
|
||||
cur = next;
|
||||
|
||||
@ -456,8 +456,8 @@
|
||||
dict->weight );
|
||||
font_info->italic_angle = dict->italic_angle;
|
||||
font_info->is_fixed_pitch = dict->is_fixed_pitch;
|
||||
font_info->underline_position = (FT_Short)dict->underline_position;
|
||||
font_info->underline_thickness = (FT_UShort)dict->underline_thickness;
|
||||
font_info->underline_position = dict->underline_position;
|
||||
font_info->underline_thickness = dict->underline_thickness;
|
||||
|
||||
cff->font_info = font_info;
|
||||
}
|
||||
|
||||
@ -2014,8 +2014,8 @@
|
||||
/* set defaults */
|
||||
FT_ZERO( top );
|
||||
|
||||
top->underline_position = -( 100L << 16 );
|
||||
top->underline_thickness = 50L << 16;
|
||||
top->underline_position = -100;
|
||||
top->underline_thickness = 50;
|
||||
top->charstring_type = 2;
|
||||
top->font_matrix.xx = 0x10000L;
|
||||
top->font_matrix.yy = 0x10000L;
|
||||
|
||||
@ -846,10 +846,8 @@
|
||||
cffface->height = (FT_Short)( cffface->ascender -
|
||||
cffface->descender );
|
||||
|
||||
cffface->underline_position =
|
||||
(FT_Short)( dict->underline_position >> 16 );
|
||||
cffface->underline_thickness =
|
||||
(FT_Short)( dict->underline_thickness >> 16 );
|
||||
cffface->underline_position = (FT_Short)dict->underline_position;
|
||||
cffface->underline_thickness = (FT_Short)dict->underline_thickness;
|
||||
|
||||
/* retrieve font family & style name */
|
||||
if ( dict->family_name )
|
||||
|
||||
@ -30,8 +30,8 @@
|
||||
CFF_FIELD_STRING ( 4, weight, "Weight" )
|
||||
CFF_FIELD_BOOL ( 0x101, is_fixed_pitch, "isFixedPitch" )
|
||||
CFF_FIELD_FIXED ( 0x102, italic_angle, "ItalicAngle" )
|
||||
CFF_FIELD_FIXED ( 0x103, underline_position, "UnderlinePosition" )
|
||||
CFF_FIELD_FIXED ( 0x104, underline_thickness, "UnderlineThickness" )
|
||||
CFF_FIELD_NUM ( 0x103, underline_position, "UnderlinePosition" )
|
||||
CFF_FIELD_NUM ( 0x104, underline_thickness, "UnderlineThickness" )
|
||||
CFF_FIELD_NUM ( 0x105, paint_type, "PaintType" )
|
||||
CFF_FIELD_NUM ( 0x106, charstring_type, "CharstringType" )
|
||||
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
T1_FIELD_STRING( "FullName", full_name, 0 )
|
||||
T1_FIELD_STRING( "FamilyName", family_name, 0 )
|
||||
T1_FIELD_STRING( "Weight", weight, 0 )
|
||||
T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 )
|
||||
T1_FIELD_FIXED ( "ItalicAngle", italic_angle, 0 )
|
||||
T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 )
|
||||
T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 )
|
||||
T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 )
|
||||
|
||||
@ -35,10 +35,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#define COMPUTE_INFLEXS /* compute inflection points to optimize `S' */
|
||||
/* and similar glyphs */
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
@ -920,117 +916,6 @@
|
||||
#define psh_corner_orientation ft_corner_orientation
|
||||
|
||||
|
||||
#ifdef COMPUTE_INFLEXS
|
||||
|
||||
/* compute all inflex points in a given glyph */
|
||||
static void
|
||||
psh_glyph_compute_inflections( PSH_Glyph glyph )
|
||||
{
|
||||
FT_UInt n;
|
||||
|
||||
|
||||
for ( n = 0; n < glyph->num_contours; n++ )
|
||||
{
|
||||
PSH_Point first, start, end, before, after;
|
||||
FT_Pos in_x, in_y, out_x, out_y;
|
||||
FT_Int orient_prev, orient_cur;
|
||||
FT_Int finished = 0;
|
||||
|
||||
|
||||
/* we need at least 4 points to create an inflection point */
|
||||
if ( glyph->contours[n].count < 4 )
|
||||
continue;
|
||||
|
||||
/* compute first segment in contour */
|
||||
first = glyph->contours[n].start;
|
||||
|
||||
start = end = first;
|
||||
do
|
||||
{
|
||||
end = end->next;
|
||||
if ( end == first )
|
||||
goto Skip;
|
||||
|
||||
in_x = end->org_u - start->org_u;
|
||||
in_y = end->org_v - start->org_v;
|
||||
|
||||
} while ( in_x == 0 && in_y == 0 );
|
||||
|
||||
/* extend the segment start whenever possible */
|
||||
before = start;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
start = before;
|
||||
before = before->prev;
|
||||
if ( before == first )
|
||||
goto Skip;
|
||||
|
||||
out_x = start->org_u - before->org_u;
|
||||
out_y = start->org_v - before->org_v;
|
||||
|
||||
} while ( out_x == 0 && out_y == 0 );
|
||||
|
||||
orient_prev = psh_corner_orientation( in_x, in_y, out_x, out_y );
|
||||
|
||||
} while ( orient_prev == 0 );
|
||||
|
||||
first = start;
|
||||
in_x = out_x;
|
||||
in_y = out_y;
|
||||
|
||||
/* now, process all segments in the contour */
|
||||
do
|
||||
{
|
||||
/* first, extend current segment's end whenever possible */
|
||||
after = end;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
end = after;
|
||||
after = after->next;
|
||||
if ( after == first )
|
||||
finished = 1;
|
||||
|
||||
out_x = after->org_u - end->org_u;
|
||||
out_y = after->org_v - end->org_v;
|
||||
|
||||
} while ( out_x == 0 && out_y == 0 );
|
||||
|
||||
orient_cur = psh_corner_orientation( in_x, in_y, out_x, out_y );
|
||||
|
||||
} while ( orient_cur == 0 );
|
||||
|
||||
if ( ( orient_cur ^ orient_prev ) < 0 )
|
||||
{
|
||||
do
|
||||
{
|
||||
psh_point_set_inflex( start );
|
||||
start = start->next;
|
||||
}
|
||||
while ( start != end );
|
||||
|
||||
psh_point_set_inflex( start );
|
||||
}
|
||||
|
||||
start = end;
|
||||
end = after;
|
||||
orient_prev = orient_cur;
|
||||
in_x = out_x;
|
||||
in_y = out_y;
|
||||
|
||||
} while ( !finished );
|
||||
|
||||
Skip:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* COMPUTE_INFLEXS */
|
||||
|
||||
|
||||
static void
|
||||
psh_glyph_done( PSH_Glyph glyph )
|
||||
{
|
||||
@ -1258,11 +1143,6 @@
|
||||
glyph->outline = outline;
|
||||
glyph->globals = globals;
|
||||
|
||||
#ifdef COMPUTE_INFLEXS
|
||||
psh_glyph_load_points( glyph, 0 );
|
||||
psh_glyph_compute_inflections( glyph );
|
||||
#endif /* COMPUTE_INFLEXS */
|
||||
|
||||
/* now deal with hints tables */
|
||||
error = psh_hint_table_init( &glyph->hint_tables [0],
|
||||
&ps_hints->dimension[0].hints,
|
||||
@ -1285,122 +1165,47 @@
|
||||
}
|
||||
|
||||
|
||||
/* compute all extrema in a glyph for a given dimension */
|
||||
/* compute all extreme and inflection points */
|
||||
/* in a glyph for a given dimension */
|
||||
static void
|
||||
psh_glyph_compute_extrema( PSH_Glyph glyph )
|
||||
{
|
||||
FT_UInt n;
|
||||
|
||||
|
||||
/* first of all, compute all local extrema */
|
||||
for ( n = 0; n < glyph->num_contours; n++ )
|
||||
{
|
||||
PSH_Point first = glyph->contours[n].start;
|
||||
PSH_Point point, before, after;
|
||||
PSH_Point first, point, before, after;
|
||||
|
||||
|
||||
if ( glyph->contours[n].count == 0 )
|
||||
/* we need at least 3 points to create an extremum */
|
||||
if ( glyph->contours[n].count < 3 )
|
||||
continue;
|
||||
|
||||
point = first;
|
||||
before = point;
|
||||
first = glyph->contours[n].start;
|
||||
point = first->prev;
|
||||
after = first;
|
||||
|
||||
do
|
||||
{
|
||||
before = before->prev;
|
||||
if ( before == first )
|
||||
goto Skip;
|
||||
|
||||
} while ( before->org_u == point->org_u );
|
||||
|
||||
first = point = before->next;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
after = point;
|
||||
do
|
||||
{
|
||||
after = after->next;
|
||||
if ( after == first )
|
||||
goto Next;
|
||||
|
||||
} while ( after->org_u == point->org_u );
|
||||
|
||||
if ( before->org_u < point->org_u )
|
||||
{
|
||||
if ( after->org_u < point->org_u )
|
||||
{
|
||||
/* local maximum */
|
||||
goto Extremum;
|
||||
}
|
||||
}
|
||||
else /* before->org_u > point->org_u */
|
||||
{
|
||||
if ( after->org_u > point->org_u )
|
||||
{
|
||||
/* local minimum */
|
||||
Extremum:
|
||||
do
|
||||
{
|
||||
psh_point_set_extremum( point );
|
||||
point = point->next;
|
||||
|
||||
} while ( point != after );
|
||||
}
|
||||
}
|
||||
|
||||
before = after->prev;
|
||||
before = point;
|
||||
point = after;
|
||||
after = point->next;
|
||||
|
||||
} /* for */
|
||||
if ( ( before->org_u < point->org_u && point->org_u < after->org_u ) ||
|
||||
( before->org_u > point->org_u && point->org_u > after->org_u ) )
|
||||
continue;
|
||||
|
||||
Next:
|
||||
;
|
||||
}
|
||||
/* otherwise this is either extremum or inflection point */
|
||||
psh_point_set_extremum( point );
|
||||
|
||||
/* for each extremum, determine its direction along the */
|
||||
/* orthogonal axis */
|
||||
for ( n = 0; n < glyph->num_points; n++ )
|
||||
{
|
||||
PSH_Point point, before, after;
|
||||
/* also note its direction */
|
||||
if ( before->org_v < after->org_v )
|
||||
psh_point_set_positive( point );
|
||||
else if ( before->org_v > after->org_v )
|
||||
psh_point_set_negative( point );
|
||||
|
||||
|
||||
point = &glyph->points[n];
|
||||
before = point;
|
||||
after = point;
|
||||
|
||||
if ( psh_point_is_extremum( point ) )
|
||||
{
|
||||
do
|
||||
{
|
||||
before = before->prev;
|
||||
if ( before == point )
|
||||
goto Skip;
|
||||
|
||||
} while ( before->org_v == point->org_v );
|
||||
|
||||
do
|
||||
{
|
||||
after = after->next;
|
||||
if ( after == point )
|
||||
goto Skip;
|
||||
|
||||
} while ( after->org_v == point->org_v );
|
||||
}
|
||||
|
||||
if ( before->org_v < point->org_v &&
|
||||
after->org_v > point->org_v )
|
||||
{
|
||||
psh_point_set_positive( point );
|
||||
}
|
||||
else if ( before->org_v > point->org_v &&
|
||||
after->org_v < point->org_v )
|
||||
{
|
||||
psh_point_set_negative( point );
|
||||
}
|
||||
|
||||
Skip:
|
||||
;
|
||||
} while ( after != first );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1836,8 +1641,7 @@
|
||||
point->dir_in != point->dir_out )
|
||||
continue;
|
||||
|
||||
if ( !psh_point_is_extremum( point ) &&
|
||||
!psh_point_is_inflex( point ) )
|
||||
if ( !psh_point_is_extremum( point ) )
|
||||
continue;
|
||||
|
||||
point->flags &= ~PSH_POINT_SMOOTH;
|
||||
|
||||
@ -376,36 +376,24 @@
|
||||
/* not. We simply need to compare the vertical scale */
|
||||
/* parameter to the raw bluescale value. Here is why: */
|
||||
/* */
|
||||
/* We need to suppress overshoots for all pointsizes. */
|
||||
/* At 300dpi that satisfies: */
|
||||
/* The specs explain how the bluescale is calculated */
|
||||
/* from the desired maximum rounded pointsize at 300 dpi */
|
||||
/* and assuming upem of 1000. */
|
||||
/* */
|
||||
/* pointsize < 240*bluescale + 0.49 */
|
||||
/* bluescale = ( pointsize - 0.49 ) / 240 */
|
||||
/* */
|
||||
/* This corresponds to: */
|
||||
/* For unrounded pointsize in general terms */
|
||||
/* */
|
||||
/* pixelsize < 1000*bluescale + 49/24 */
|
||||
/* bluescale = ( pointsize * dpi / 72 ) / upem */
|
||||
/* */
|
||||
/* scale*EM_Size < 1000*bluescale + 49/24 */
|
||||
/* which is */
|
||||
/* */
|
||||
/* However, for normal Type 1 fonts, EM_Size is 1000! */
|
||||
/* We thus only check: */
|
||||
/* bluescale = pixelsize / upem */
|
||||
/* */
|
||||
/* scale < bluescale + 49/24000 */
|
||||
/* Therefore, the bluescale value can be used directly */
|
||||
/* as a scale limit, now that it is in comparable units */
|
||||
/* */
|
||||
/* which we shorten to */
|
||||
/* */
|
||||
/* "scale < bluescale" */
|
||||
/* */
|
||||
/* Note that `blue_scale' is stored 1000 times its real */
|
||||
/* value, and that `scale' converts from font units to */
|
||||
/* fractional pixels. */
|
||||
/* */
|
||||
|
||||
/* 1000 / 64 = 125 / 8 */
|
||||
if ( scale >= 0x20C49BAL )
|
||||
blues->no_overshoots = FT_BOOL( scale < blues->blue_scale * 8 / 125 );
|
||||
else
|
||||
blues->no_overshoots = FT_BOOL( scale * 125 < blues->blue_scale * 8 );
|
||||
blues->no_overshoots = FT_BOOL( scale < blues->blue_scale );
|
||||
|
||||
/* */
|
||||
/* The blue threshold is the font units distance under */
|
||||
@ -420,8 +408,8 @@
|
||||
FT_Int threshold = blues->blue_shift;
|
||||
|
||||
|
||||
while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
|
||||
threshold--;
|
||||
if ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
|
||||
threshold = 32 * 0x10000L / scale;
|
||||
|
||||
blues->blue_threshold = threshold;
|
||||
}
|
||||
@ -708,7 +696,6 @@
|
||||
|
||||
/* limit the BlueScale value to `1 / max_of_blue_zone_heights' */
|
||||
{
|
||||
FT_Fixed max_scale;
|
||||
FT_Short max_height = 1;
|
||||
|
||||
|
||||
@ -725,11 +712,12 @@
|
||||
priv->family_other_blues,
|
||||
max_height );
|
||||
|
||||
/* BlueScale is scaled 1000 times */
|
||||
max_scale = FT_DivFix( 1000, max_height );
|
||||
globals->blues.blue_scale = priv->blue_scale < max_scale
|
||||
? priv->blue_scale
|
||||
: max_scale;
|
||||
/* restrict BlueScale value that is amplified 1000-fold and */
|
||||
/* rescale it to be comparable to the metrics scale */
|
||||
if ( FT_MulFix( max_height, priv->blue_scale ) < 1000 )
|
||||
globals->blues.blue_scale = priv->blue_scale * 8 / 125;
|
||||
else
|
||||
globals->blues.blue_scale = 64 * 0x10000L / max_height;
|
||||
}
|
||||
|
||||
globals->blues.blue_shift = priv->blue_shift;
|
||||
|
||||
@ -420,10 +420,7 @@
|
||||
if ( populate_map_and_metrics )
|
||||
{
|
||||
/* this doesn't overflow: 0x7FFF * 0x7FFF * 4 < 2^32 */
|
||||
FT_ULong size = map->rows * (FT_ULong)map->pitch;
|
||||
|
||||
|
||||
error = ft_glyphslot_alloc_bitmap( slot, size );
|
||||
error = ft_glyphslot_alloc_bitmap( slot );
|
||||
if ( error )
|
||||
goto DestroyExit;
|
||||
}
|
||||
|
||||
@ -1142,12 +1142,7 @@
|
||||
FT_Error error;
|
||||
|
||||
|
||||
/* XXX: I don't know whether this is correct, since
|
||||
* tt_face_find_bdf_prop only returns something correct if we have
|
||||
* previously selected a size that is listed in the BDF table.
|
||||
* Should we change the BDF table format to include single offsets
|
||||
* for `CHARSET_REGISTRY' and `CHARSET_ENCODING'?
|
||||
*/
|
||||
/* We expect that a bitmap strike has been selected. */
|
||||
error = tt_face_find_bdf_prop( face, "CHARSET_REGISTRY", ®istry );
|
||||
if ( !error )
|
||||
{
|
||||
|
||||
@ -1043,7 +1043,6 @@
|
||||
FT_ULong total_n_points = 0;
|
||||
FT_UShort n_points_contour;
|
||||
FT_UInt j;
|
||||
FT_ULong flag_size;
|
||||
FT_ULong triplet_size;
|
||||
FT_ULong triplet_bytes_used;
|
||||
FT_Bool have_overlap = FALSE;
|
||||
@ -1088,8 +1087,8 @@
|
||||
}
|
||||
substreams[N_POINTS_STREAM].offset = FT_STREAM_POS();
|
||||
|
||||
flag_size = total_n_points;
|
||||
if ( flag_size > substreams[FLAG_STREAM].size )
|
||||
points_size += total_n_points;
|
||||
if ( points_size > substreams[FLAG_STREAM].size )
|
||||
goto Fail;
|
||||
|
||||
flags_buf = stream->base + substreams[FLAG_STREAM].offset;
|
||||
@ -1106,8 +1105,7 @@
|
||||
triplet_bytes_used = 0;
|
||||
|
||||
/* Create array to store point information. */
|
||||
points_size = total_n_points;
|
||||
if ( FT_QNEW_ARRAY( points, points_size ) )
|
||||
if ( FT_QNEW_ARRAY( points, total_n_points ) )
|
||||
goto Fail;
|
||||
|
||||
if ( triplet_decode( flags_buf,
|
||||
@ -1118,7 +1116,7 @@
|
||||
&triplet_bytes_used ) )
|
||||
goto Fail;
|
||||
|
||||
substreams[FLAG_STREAM].offset += flag_size;
|
||||
substreams[FLAG_STREAM].offset += total_n_points;
|
||||
substreams[GLYPH_STREAM].offset += triplet_bytes_used;
|
||||
|
||||
if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) ||
|
||||
|
||||
@ -1749,7 +1749,6 @@
|
||||
FT_UInt x, y;
|
||||
FT_Byte b, g, r, alpha;
|
||||
|
||||
FT_ULong size;
|
||||
FT_Byte* src;
|
||||
FT_Byte* dst;
|
||||
|
||||
@ -1767,13 +1766,9 @@
|
||||
dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4;
|
||||
dstSlot->bitmap.num_grays = 256;
|
||||
|
||||
size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
|
||||
|
||||
error = ft_glyphslot_alloc_bitmap( dstSlot, size );
|
||||
error = ft_glyphslot_alloc_bitmap( dstSlot );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1805,8 +1800,7 @@
|
||||
FT_Byte* q;
|
||||
|
||||
|
||||
size = rows * pitch;
|
||||
if ( FT_ALLOC( buf, size ) )
|
||||
if ( FT_ALLOC_MULT( buf, rows, pitch ) )
|
||||
return error;
|
||||
|
||||
p = dstSlot->bitmap.buffer;
|
||||
|
||||
@ -547,7 +547,6 @@
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_UInt width, height;
|
||||
FT_Bitmap* map = decoder->bitmap;
|
||||
FT_ULong size;
|
||||
|
||||
|
||||
if ( !decoder->metrics_loaded )
|
||||
@ -599,17 +598,11 @@
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
size = map->rows * (FT_ULong)map->pitch;
|
||||
|
||||
/* check that there is no empty image */
|
||||
if ( size == 0 )
|
||||
goto Exit; /* exit successfully! */
|
||||
|
||||
if ( metrics_only )
|
||||
goto Exit; /* only metrics are requested */
|
||||
|
||||
error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size );
|
||||
if ( error )
|
||||
error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph );
|
||||
if ( error || !map->buffer )
|
||||
goto Exit;
|
||||
|
||||
decoder->bitmap_allocated = 1;
|
||||
|
||||
@ -1804,7 +1804,7 @@ typedef ptrdiff_t FT_PtrDist;
|
||||
FT_FILL_RULE( coverage, cover, fill );
|
||||
|
||||
span[n].coverage = (unsigned char)coverage;
|
||||
span[n].x = (short)x;
|
||||
span[n].x = (unsigned short)x;
|
||||
span[n].len = (unsigned short)( cell->x - x );
|
||||
|
||||
if ( ++n == FT_MAX_GRAY_SPANS )
|
||||
@ -1823,7 +1823,7 @@ typedef ptrdiff_t FT_PtrDist;
|
||||
FT_FILL_RULE( coverage, area, fill );
|
||||
|
||||
span[n].coverage = (unsigned char)coverage;
|
||||
span[n].x = (short)cell->x;
|
||||
span[n].x = (unsigned short)cell->x;
|
||||
span[n].len = 1;
|
||||
|
||||
if ( ++n == FT_MAX_GRAY_SPANS )
|
||||
|
||||
@ -80,6 +80,7 @@
|
||||
{
|
||||
unsigned char* origin; /* pixmap origin at the bottom-left */
|
||||
int pitch; /* pitch to go down one row */
|
||||
unsigned char wght[5]; /* filtering weights */
|
||||
|
||||
} TOrigin;
|
||||
|
||||
@ -274,6 +275,32 @@
|
||||
}
|
||||
|
||||
|
||||
/* This function applies a horizontal filter in direct rendering mode */
|
||||
static void
|
||||
ft_smooth_lcd_spans( int y,
|
||||
int count,
|
||||
const FT_Span* spans,
|
||||
void* target_ ) /* TOrigin* */
|
||||
{
|
||||
TOrigin* target = (TOrigin*)target_;
|
||||
|
||||
unsigned char* dst_line = target->origin - y * target->pitch - 2;
|
||||
unsigned char* dst;
|
||||
unsigned short w;
|
||||
|
||||
|
||||
for ( ; count--; spans++ )
|
||||
for ( dst = dst_line + spans->x, w = spans->len; w--; dst++ )
|
||||
{
|
||||
dst[0] += ( spans->coverage * target->wght[0] + 85 ) >> 8;
|
||||
dst[1] += ( spans->coverage * target->wght[1] + 85 ) >> 8;
|
||||
dst[2] += ( spans->coverage * target->wght[2] + 85 ) >> 8;
|
||||
dst[3] += ( spans->coverage * target->wght[3] + 85 ) >> 8;
|
||||
dst[4] += ( spans->coverage * target->wght[4] + 85 ) >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FT_Error
|
||||
ft_smooth_raster_lcd( FT_Renderer render,
|
||||
FT_Outline* outline,
|
||||
@ -285,11 +312,47 @@
|
||||
FT_Vector* vec;
|
||||
|
||||
FT_Raster_Params params;
|
||||
TOrigin target;
|
||||
|
||||
|
||||
params.target = bitmap;
|
||||
params.source = outline;
|
||||
params.flags = FT_RASTER_FLAG_AA;
|
||||
if ( render->root.library->lcd_weights[2] )
|
||||
{
|
||||
/* Reject outlines that are too wide for 16-bit FT_Span. */
|
||||
/* Other limits are applied upstream with the same error code. */
|
||||
if ( bitmap->width > 0x7FFF )
|
||||
return FT_THROW( Raster_Overflow );
|
||||
|
||||
/* Set up direct rendering for instant filtering. */
|
||||
params.source = outline;
|
||||
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
|
||||
params.gray_spans = ft_smooth_lcd_spans;
|
||||
params.user = ⌖
|
||||
|
||||
params.clip_box.xMin = 0;
|
||||
params.clip_box.yMin = 0;
|
||||
params.clip_box.xMax = bitmap->width;
|
||||
params.clip_box.yMax = bitmap->rows;
|
||||
|
||||
if ( bitmap->pitch < 0 )
|
||||
target.origin = bitmap->buffer;
|
||||
else
|
||||
target.origin = bitmap->buffer
|
||||
+ ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
|
||||
|
||||
target.pitch = bitmap->pitch;
|
||||
|
||||
target.wght[0] = render->root.library->lcd_weights[0];
|
||||
target.wght[1] = render->root.library->lcd_weights[1];
|
||||
target.wght[2] = render->root.library->lcd_weights[2];
|
||||
target.wght[3] = render->root.library->lcd_weights[3];
|
||||
target.wght[4] = render->root.library->lcd_weights[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
params.target = bitmap;
|
||||
params.source = outline;
|
||||
params.flags = FT_RASTER_FLAG_AA;
|
||||
}
|
||||
|
||||
/* implode outline */
|
||||
for ( vec = points; vec < points_end; vec++ )
|
||||
@ -306,6 +369,32 @@
|
||||
}
|
||||
|
||||
|
||||
/* This function applies a vertical filter in direct rendering mode */
|
||||
static void
|
||||
ft_smooth_lcdv_spans( int y,
|
||||
int count,
|
||||
const FT_Span* spans,
|
||||
void* target_ ) /* TOrigin* */
|
||||
{
|
||||
TOrigin* target = (TOrigin*)target_;
|
||||
|
||||
int pitch = target->pitch;
|
||||
unsigned char* dst_line = target->origin - ( y + 2 ) * pitch;
|
||||
unsigned char* dst;
|
||||
unsigned short w;
|
||||
|
||||
|
||||
for ( ; count--; spans++ )
|
||||
for ( dst = dst_line + spans->x, w = spans->len; w--; dst++ )
|
||||
{
|
||||
dst[ 0] += ( spans->coverage * target->wght[0] + 85 ) >> 8;
|
||||
dst[ pitch] += ( spans->coverage * target->wght[1] + 85 ) >> 8;
|
||||
dst[2 * pitch] += ( spans->coverage * target->wght[2] + 85 ) >> 8;
|
||||
dst[3 * pitch] += ( spans->coverage * target->wght[3] + 85 ) >> 8;
|
||||
dst[4 * pitch] += ( spans->coverage * target->wght[4] + 85 ) >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
static FT_Error
|
||||
ft_smooth_raster_lcdv( FT_Renderer render,
|
||||
FT_Outline* outline,
|
||||
@ -317,11 +406,42 @@
|
||||
FT_Vector* vec;
|
||||
|
||||
FT_Raster_Params params;
|
||||
TOrigin target;
|
||||
|
||||
|
||||
params.target = bitmap;
|
||||
params.source = outline;
|
||||
params.flags = FT_RASTER_FLAG_AA;
|
||||
if ( render->root.library->lcd_weights[2] )
|
||||
{
|
||||
/* Set up direct rendering for instant filtering. */
|
||||
params.source = outline;
|
||||
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
|
||||
params.gray_spans = ft_smooth_lcdv_spans;
|
||||
params.user = ⌖
|
||||
|
||||
params.clip_box.xMin = 0;
|
||||
params.clip_box.yMin = 0;
|
||||
params.clip_box.xMax = bitmap->width;
|
||||
params.clip_box.yMax = bitmap->rows;
|
||||
|
||||
if ( bitmap->pitch < 0 )
|
||||
target.origin = bitmap->buffer;
|
||||
else
|
||||
target.origin = bitmap->buffer
|
||||
+ ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
|
||||
|
||||
target.pitch = bitmap->pitch;
|
||||
|
||||
target.wght[0] = render->root.library->lcd_weights[0];
|
||||
target.wght[1] = render->root.library->lcd_weights[1];
|
||||
target.wght[2] = render->root.library->lcd_weights[2];
|
||||
target.wght[3] = render->root.library->lcd_weights[3];
|
||||
target.wght[4] = render->root.library->lcd_weights[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
params.target = bitmap;
|
||||
params.source = outline;
|
||||
params.flags = FT_RASTER_FLAG_AA;
|
||||
}
|
||||
|
||||
/* implode outline */
|
||||
for ( vec = points; vec < points_end; vec++ )
|
||||
@ -494,12 +614,6 @@
|
||||
else
|
||||
y_shift += 64 * (FT_Int)bitmap->rows;
|
||||
|
||||
if ( origin )
|
||||
{
|
||||
x_shift += origin->x;
|
||||
y_shift += origin->y;
|
||||
}
|
||||
|
||||
/* translate outline to render it into the bitmap */
|
||||
if ( x_shift || y_shift )
|
||||
FT_Outline_Translate( outline, x_shift, y_shift );
|
||||
@ -527,33 +641,6 @@
|
||||
error = ft_smooth_raster_lcd ( render, outline, bitmap );
|
||||
else if ( mode == FT_RENDER_MODE_LCD_V )
|
||||
error = ft_smooth_raster_lcdv( render, outline, bitmap );
|
||||
|
||||
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
|
||||
|
||||
/* finally apply filtering */
|
||||
{
|
||||
FT_Byte* lcd_weights;
|
||||
FT_Bitmap_LcdFilterFunc lcd_filter_func;
|
||||
|
||||
|
||||
/* Per-face LCD filtering takes priority if set up. */
|
||||
if ( slot->face && slot->face->internal->lcd_filter_func )
|
||||
{
|
||||
lcd_weights = slot->face->internal->lcd_weights;
|
||||
lcd_filter_func = slot->face->internal->lcd_filter_func;
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_weights = slot->library->lcd_weights;
|
||||
lcd_filter_func = slot->library->lcd_filter_func;
|
||||
}
|
||||
|
||||
if ( lcd_filter_func )
|
||||
lcd_filter_func( bitmap, lcd_weights );
|
||||
}
|
||||
|
||||
#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
|
||||
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
@ -2217,6 +2217,10 @@
|
||||
exec = size->context;
|
||||
|
||||
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
|
||||
/* reset backward compatibility; note that */
|
||||
/* the CVT program always runs without it */
|
||||
exec->backward_compatibility = 0;
|
||||
|
||||
if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
|
||||
{
|
||||
grayscale = FALSE;
|
||||
@ -2253,9 +2257,7 @@
|
||||
return error;
|
||||
}
|
||||
|
||||
error = TT_Load_Context( exec, face, size );
|
||||
if ( error )
|
||||
return error;
|
||||
TT_Load_Context( exec, face, size );
|
||||
|
||||
/* check whether the cvt program has disabled hinting */
|
||||
if ( size->GS.instruct_control & 1 )
|
||||
@ -2283,8 +2285,7 @@
|
||||
mode != FT_RENDER_MODE_MONO &&
|
||||
!FT_IS_TRICKY( glyph->face ) )
|
||||
exec->backward_compatibility = ( size->GS.instruct_control & 4 ) ^ 4;
|
||||
else
|
||||
exec->backward_compatibility = 0;
|
||||
|
||||
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */
|
||||
|
||||
loader->exec = exec;
|
||||
|
||||
@ -697,11 +697,9 @@
|
||||
if ( long_words )
|
||||
per_region_size *= 2;
|
||||
|
||||
if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) )
|
||||
if ( FT_QALLOC_MULT( varData->deltaSet, item_count, per_region_size ) )
|
||||
goto Exit;
|
||||
if ( FT_Stream_Read( stream,
|
||||
varData->deltaSet,
|
||||
per_region_size * item_count ) )
|
||||
if ( FT_STREAM_READ( varData->deltaSet, item_count * per_region_size ) )
|
||||
{
|
||||
FT_TRACE2(( "deltaSet read failed." ));
|
||||
error = FT_THROW( Invalid_Table );
|
||||
|
||||
@ -272,7 +272,7 @@
|
||||
*
|
||||
* Note that not all members of `TT_ExecContext` get initialized.
|
||||
*/
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
FT_LOCAL_DEF( void )
|
||||
TT_Load_Context( TT_ExecContext exec,
|
||||
TT_Face face,
|
||||
TT_Size size )
|
||||
@ -284,7 +284,7 @@
|
||||
exec->size = size;
|
||||
|
||||
/* CVT and storage are not persistent in FreeType */
|
||||
/* reset them after they might have been modifief */
|
||||
/* reset them after they might have been modified */
|
||||
exec->storage = exec->stack + exec->stackSize;
|
||||
exec->cvt = exec->storage + exec->storeSize;
|
||||
|
||||
@ -297,8 +297,6 @@
|
||||
exec->metrics = *size->metrics;
|
||||
|
||||
exec->twilight = size->twilight;
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
|
||||
@ -5457,11 +5455,11 @@
|
||||
/* single width cut-in test */
|
||||
|
||||
/* |org_dist - single_width_value| < single_width_cutin */
|
||||
if ( exc->GS.single_width_cutin > 0 &&
|
||||
org_dist < exc->GS.single_width_value +
|
||||
exc->GS.single_width_cutin &&
|
||||
org_dist > exc->GS.single_width_value -
|
||||
exc->GS.single_width_cutin )
|
||||
if ( exc->GS.single_width_cutin > 0 &&
|
||||
org_dist < ADD_LONG( exc->GS.single_width_value,
|
||||
exc->GS.single_width_cutin ) &&
|
||||
org_dist > SUB_LONG( exc->GS.single_width_value,
|
||||
exc->GS.single_width_cutin ) )
|
||||
{
|
||||
if ( org_dist >= 0 )
|
||||
org_dist = exc->GS.single_width_value;
|
||||
|
||||
@ -439,7 +439,7 @@ FT_BEGIN_HEADER
|
||||
FT_LOCAL( void )
|
||||
TT_Done_Context( TT_ExecContext exec );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
FT_LOCAL( void )
|
||||
TT_Load_Context( TT_ExecContext exec,
|
||||
TT_Face face,
|
||||
TT_Size size );
|
||||
|
||||
@ -884,9 +884,7 @@
|
||||
FT_Error error;
|
||||
|
||||
|
||||
error = TT_Load_Context( exec, face, size );
|
||||
if ( error )
|
||||
return error;
|
||||
TT_Load_Context( exec, face, size );
|
||||
|
||||
/* disable CVT and glyph programs coderange */
|
||||
TT_Clear_CodeRange( exec, tt_coderange_cvt );
|
||||
@ -952,9 +950,7 @@
|
||||
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;
|
||||
TT_Load_Context( exec, face, size );
|
||||
|
||||
/* clear storage area */
|
||||
FT_ARRAY_ZERO( exec->storage, exec->storeSize );
|
||||
@ -1043,13 +1039,15 @@
|
||||
if ( !exec )
|
||||
return FT_THROW( Could_Not_Find_Context );
|
||||
|
||||
size->context = exec;
|
||||
|
||||
exec->pedantic_hinting = pedantic;
|
||||
|
||||
exec->maxFDefs = maxp->maxFunctionDefs;
|
||||
exec->maxIDefs = maxp->maxInstructionDefs;
|
||||
|
||||
if ( FT_NEW_ARRAY( exec->FDefs, exec->maxFDefs + exec->maxIDefs ) )
|
||||
goto Exit;
|
||||
goto Fail;
|
||||
|
||||
exec->IDefs = exec->FDefs + exec->maxFDefs;
|
||||
|
||||
@ -1068,7 +1066,7 @@
|
||||
if ( FT_NEW_ARRAY( exec->stack,
|
||||
exec->stackSize +
|
||||
(FT_Long)( exec->storeSize + exec->cvtSize ) ) )
|
||||
goto Exit;
|
||||
goto Fail;
|
||||
|
||||
/* reserve twilight zone and set GS before fpgm is executed, */
|
||||
/* just in case, even though fpgm should not touch them */
|
||||
@ -1079,11 +1077,10 @@
|
||||
|
||||
error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
goto Fail;
|
||||
|
||||
size->GS = tt_default_graphics_state;
|
||||
size->cvt_ready = -1;
|
||||
size->context = exec;
|
||||
|
||||
size->ttmetrics.rotated = FALSE;
|
||||
size->ttmetrics.stretched = FALSE;
|
||||
@ -1099,10 +1096,8 @@
|
||||
error = tt_size_run_fpgm( size );
|
||||
return error;
|
||||
|
||||
Exit:
|
||||
if ( error )
|
||||
tt_size_done_bytecode( size );
|
||||
|
||||
Fail:
|
||||
tt_size_done_bytecode( size );
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
T1_FIELD_DICT_FONTDICT )
|
||||
|
||||
/* we use pointers to detect modifications made by synthetic fonts */
|
||||
T1_FIELD_NUM ( "ItalicAngle", italic_angle,
|
||||
T1_FIELD_FIXED ( "ItalicAngle", italic_angle,
|
||||
T1_FIELD_DICT_FONTDICT )
|
||||
T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch,
|
||||
T1_FIELD_DICT_FONTDICT )
|
||||
|
||||
@ -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.
|
||||
*
|
||||
* <p>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)}.</p>
|
||||
*
|
||||
* @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);
|
||||
|
||||
@ -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<AttrContext> env = getAttrContext(path.getTreePath());
|
||||
Log.DeferredDiagnosticHandler deferredDiagnosticHandler = log.new DeferredDiagnosticHandler();
|
||||
JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
|
||||
|
||||
try {
|
||||
Env<AttrContext> 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<Type> paramTypes;
|
||||
if (ref.paramTypes == null)
|
||||
paramTypes = null;
|
||||
else {
|
||||
ListBuffer<Type> lb = new ListBuffer<>();
|
||||
for (List<JCTree> l = (List<JCTree>) 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<AttrContext> env) {
|
||||
|
||||
if (type.isPrimitive() || type.getKind() == TypeKind.PACKAGE || type.getKind() == TypeKind.MODULE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<Type> paramTypes;
|
||||
if (ref.paramTypes == null)
|
||||
paramTypes = null;
|
||||
else {
|
||||
ListBuffer<Type> lb = new ListBuffer<>();
|
||||
for (List<JCTree> l = (List<JCTree>) 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)
|
||||
|
||||
@ -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) == '/';
|
||||
|
||||
});
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user