Skip to content

8353230: Emoji rendering regression after JDK-8208377 #24412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions src/java.desktop/macosx/classes/sun/font/CCharToGlyphMapper.java
Original file line number Diff line number Diff line change
@@ -47,12 +47,12 @@ public int getNumGlyphs() {
}

public boolean canDisplay(char ch) {
int glyph = charToGlyph(ch);
int glyph = charToGlyph(ch, false);
return glyph != missingGlyph;
}

public boolean canDisplay(int cp) {
int glyph = charToGlyph(cp);
int glyph = charToGlyph(cp, false);
return glyph != missingGlyph;
}

@@ -89,44 +89,52 @@ public synchronized boolean charsToGlyphsNS(int count,
}

public synchronized int charToGlyph(char unicode) {
int glyph = cache.get(unicode);
return charToGlyph(unicode, false);
}

private int charToGlyph(char unicode, boolean raw) {
int glyph = cache.get(unicode, raw);
if (glyph != 0) return glyph;

if (FontUtilities.isDefaultIgnorable(unicode)) {
glyph = INVISIBLE_GLYPH_ID;
} else {
final char[] unicodeArray = new char[] { unicode };
final int[] glyphArray = new int[1];
nativeCharsToGlyphs(fFont.getNativeFontPtr(), 1, unicodeArray, glyphArray);
glyph = glyphArray[0];
}
final char[] unicodeArray = new char[] { unicode };
final int[] glyphArray = new int[1];
nativeCharsToGlyphs(fFont.getNativeFontPtr(), 1, unicodeArray, glyphArray);
glyph = glyphArray[0];

cache.put(unicode, glyph);

return glyph;
}

public synchronized int charToGlyph(int unicode) {
return charToGlyph(unicode, false);
}

public synchronized int charToGlyphRaw(int unicode) {
return charToGlyph(unicode, true);
}

private int charToGlyph(int unicode, boolean raw) {
if (unicode >= 0x10000) {
int[] glyphs = new int[2];
char[] surrogates = new char[2];
int base = unicode - 0x10000;
surrogates[0] = (char)((base >>> 10) + HI_SURROGATE_START);
surrogates[1] = (char)((base % 0x400) + LO_SURROGATE_START);
charsToGlyphs(2, surrogates, glyphs);
cache.get(2, surrogates, glyphs, raw);
return glyphs[0];
} else {
return charToGlyph((char)unicode);
return charToGlyph((char) unicode, raw);
}
}

public synchronized void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {
cache.get(count, unicodes, glyphs);
cache.get(count, unicodes, glyphs, false);
}

public synchronized void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
for (int i = 0; i < count; i++) {
glyphs[i] = charToGlyph(unicodes[i]);
glyphs[i] = charToGlyph(unicodes[i], false);
}
}

@@ -153,7 +161,11 @@ private class Cache {
firstLayerCache[1] = 1;
}

public synchronized int get(final int index) {
public synchronized int get(final int index, final boolean raw) {
if (!raw && FontUtilities.isDefaultIgnorable(index)) {
return INVISIBLE_GLYPH_ID;
}

if (index < FIRST_LAYER_SIZE) {
// catch common glyphcodes
return firstLayerCache[index];
@@ -224,7 +236,7 @@ public void put(final int index, final int value) {
}
}

public synchronized void get(int count, char[] indices, int[] values)
public synchronized void get(int count, char[] indices, int[] values, boolean raw)
{
// "missed" is the count of 'char' that are not mapped.
// Surrogates count for 2.
@@ -246,16 +258,13 @@ public synchronized void get(int count, char[] indices, int[] values)
}
}

final int value = get(code);
final int value = get(code, raw);
if (value != 0 && value != -1) {
values[i] = value;
if (code >= 0x10000) {
values[i+1] = INVISIBLE_GLYPH_ID;
i++;
}
} else if (FontUtilities.isDefaultIgnorable(code)) {
values[i] = INVISIBLE_GLYPH_ID;
put(code, INVISIBLE_GLYPH_ID);
} else {
values[i] = 0;
put(code, -1);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -86,6 +86,13 @@ public int charToVariationGlyph(int unicode, int variationSelector) {
return charToGlyph(unicode);
}

public int charToVariationGlyphRaw(int unicode, int variationSelector) {
// Override this if variation selector is supported.
return charToGlyphRaw(unicode);
}

public abstract int charToGlyphRaw(int unicode);

public abstract int getNumGlyphs();

public abstract void charsToGlyphs(int count,
55 changes: 22 additions & 33 deletions src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,6 @@ public class CompositeGlyphMapper extends CharToGlyphMapper {
public static final int BLOCKSZ = 256;
public static final int MAXUNICODE = NBLOCKS*BLOCKSZ;


CompositeFont font;
CharToGlyphMapper[] slotMappers;
int[][] glyphMaps;
@@ -96,7 +95,7 @@ private int getCachedGlyphCode(int unicode) {

private void setCachedGlyphCode(int unicode, int glyphCode) {
if (unicode >= MAXUNICODE) {
return; // don't cache surrogates
return; // don't cache surrogates
}
int index0 = unicode >> 8;
if (glyphMaps[index0] == null) {
@@ -117,12 +116,18 @@ private CharToGlyphMapper getSlotMapper(int slot) {
return mapper;
}

private int convertToGlyph(int unicode) {

private int getGlyph(int unicode, boolean raw) {
if (!raw && FontUtilities.isDefaultIgnorable(unicode)) {
return INVISIBLE_GLYPH_ID;
}
int glyphCode = getCachedGlyphCode(unicode);
if (glyphCode != UNINITIALIZED_GLYPH) {
return glyphCode;
}
for (int slot = 0; slot < font.numSlots; slot++) {
if (!hasExcludes || !font.isExcludedChar(slot, unicode)) {
CharToGlyphMapper mapper = getSlotMapper(slot);
int glyphCode = mapper.charToGlyph(unicode);
glyphCode = mapper.charToGlyphRaw(unicode);
if (glyphCode != mapper.getMissingGlyphCode()) {
glyphCode = compositeGlyphCode(slot, glyphCode);
setCachedGlyphCode(unicode, glyphCode);
@@ -155,12 +160,13 @@ public int getNumGlyphs() {
return numGlyphs;
}

public int charToGlyph(int unicode) {
public int charToGlyphRaw(int unicode) {
int glyphCode = getGlyph(unicode, true);
return glyphCode;
}

int glyphCode = getCachedGlyphCode(unicode);
if (glyphCode == UNINITIALIZED_GLYPH) {
glyphCode = convertToGlyph(unicode);
}
public int charToGlyph(int unicode) {
int glyphCode = getGlyph(unicode, false);
return glyphCode;
}

@@ -176,11 +182,7 @@ public int charToGlyph(int unicode, int prefSlot) {
}

public int charToGlyph(char unicode) {

int glyphCode = getCachedGlyphCode(unicode);
if (glyphCode == UNINITIALIZED_GLYPH) {
glyphCode = convertToGlyph(unicode);
}
int glyphCode = getGlyph(unicode, false);
return glyphCode;
}

@@ -206,10 +208,7 @@ public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) {
}
}

int gc = glyphs[i] = getCachedGlyphCode(code);
if (gc == UNINITIALIZED_GLYPH) {
glyphs[i] = convertToGlyph(code);
}
glyphs[i] = getGlyph(code, false);

if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
continue;
@@ -243,31 +242,21 @@ public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {
code = (code - HI_SURROGATE_START) *
0x400 + low - LO_SURROGATE_START + 0x10000;

int gc = glyphs[i] = getCachedGlyphCode(code);
if (gc == UNINITIALIZED_GLYPH) {
glyphs[i] = convertToGlyph(code);
}
glyphs[i] = getGlyph(code, false);
i += 1; // Empty glyph slot after surrogate
glyphs[i] = INVISIBLE_GLYPH_ID;
continue;
}
}

int gc = glyphs[i] = getCachedGlyphCode(code);
if (gc == UNINITIALIZED_GLYPH) {
glyphs[i] = convertToGlyph(code);
}
glyphs[i] = getGlyph(code, false);
}
}

public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
for (int i=0; i<count; i++) {
int code = unicodes[i];

glyphs[i] = getCachedGlyphCode(code);
if (glyphs[i] == UNINITIALIZED_GLYPH) {
glyphs[i] = convertToGlyph(code);
}
glyphs[i] = getGlyph(code, false);
}
}

10 changes: 9 additions & 1 deletion src/java.desktop/share/classes/sun/font/Font2D.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -535,6 +535,14 @@ public int charToVariationGlyph(int wchar, int variationSelector) {
return getMapper().charToVariationGlyph(wchar, variationSelector);
}

public int charToGlyphRaw(int wchar) {
return getMapper().charToGlyphRaw(wchar);
}

public int charToVariationGlyphRaw(int wchar, int variationSelector) {
return getMapper().charToVariationGlyphRaw(wchar, variationSelector);
}

public int getMissingGlyphCode() {
return getMapper().getMissingGlyphCode();
}
6 changes: 3 additions & 3 deletions src/java.desktop/share/classes/sun/font/HBShaper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -338,7 +338,7 @@ private static int get_nominal_glyph(
) {

Font2D font2D = scopedVars.get().font();
int glyphID = font2D.charToGlyph(unicode);
int glyphID = font2D.charToGlyphRaw(unicode);
@SuppressWarnings("restricted")
MemorySegment glyphIDPtr = glyph.reinterpret(4);
glyphIDPtr.setAtIndex(JAVA_INT, 0, glyphID);
@@ -354,7 +354,7 @@ private static int get_variation_glyph(
MemorySegment user_data /* Not used */
) {
Font2D font2D = scopedVars.get().font();
int glyphID = font2D.charToVariationGlyph(unicode, variation_selector);
int glyphID = font2D.charToVariationGlyphRaw(unicode, variation_selector);
@SuppressWarnings("restricted")
MemorySegment glyphIDPtr = glyph.reinterpret(4);
glyphIDPtr.setAtIndex(JAVA_INT, 0, glyphID);
Loading
Oops, something went wrong.