JBR-2917 Added emoji support for Windows

JBR-3951 Pass real glyph type from native code instead of guessing it by rowBytes & width

(cherry picked from commit 1a7a1db798)
This commit is contained in:
Nikita Gubarkov
2021-11-02 14:40:41 +03:00
committed by jbrbot
parent cd9144f48d
commit f738913fdd
16 changed files with 111 additions and 76 deletions

View File

@@ -627,6 +627,7 @@ CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
glyphInfo->cellInfo = NULL;
glyphInfo->subpixelResolutionX = subpixelResX;
glyphInfo->subpixelResolutionY = subpixelResY;
glyphInfo->format = (UInt8) pixelSize;
#ifdef USE_IMAGE_ALIGNED_MEMORY
glyphInfo->image = image;

View File

@@ -713,7 +713,7 @@ MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
J2dTraceLn2(J2D_TRACE_INFO, "Glyph width = %d height = %d", ginfo->width, ginfo->height);
J2dTraceLn1(J2D_TRACE_INFO, "rowBytes = %d", ginfo->rowBytes);
if (ginfo->rowBytes == ginfo->width) {
if (ginfo->format == sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE) {
// grayscale or monochrome glyph data
if (ginfo->width <= MTLTR_CACHE_CELL_WIDTH &&
ginfo->height <= MTLTR_CACHE_CELL_HEIGHT)
@@ -724,7 +724,7 @@ MTLTR_DrawGlyphList(JNIEnv *env, MTLContext *mtlc, BMTLSDOps *dstOps,
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList Grayscale no cache");
ok = MTLTR_DrawGrayscaleGlyphNoCache(mtlc, ginfo, x, y, dstOps);
}
} else if (ginfo->rowBytes == ginfo->width * 4) {
} else if (ginfo->format == sun_font_StrikeCache_PIXEL_FORMAT_BGRA) {
J2dTraceLn(J2D_TRACE_INFO, "MTLTR_DrawGlyphList color glyph no cache");
ok = MTLTR_DrawColorGlyphNoCache(mtlc, ginfo, x, y, dstOps);
flushBeforeLCD = JNI_FALSE;

View File

@@ -304,7 +304,8 @@ public class FileFontStrike extends PhysicalStrike {
intPtSize = (int) pts;
useNatives = (rotation == 0 || rotation > 0 && useNativesForRotatedText) && pts >= 3.0 && pts <= 100.0 &&
(getImageWithAdvance || desc.fmHint == INTVAL_FRACTIONALMETRICS_ON) &&
!((TrueTypeFont)fileFont).useEmbeddedBitmapsForSize(intPtSize);
!((TrueTypeFont)fileFont).useEmbeddedBitmapsForSize(intPtSize) &&
!((TrueTypeFont)fileFont).hasCOLRTable();
}
if (FontUtilities.isLogging() && FontUtilities.isWindows) {
FontUtilities.logInfo("Strike for " + fileFont + " at size = " + intPtSize +
@@ -847,14 +848,12 @@ public class FileFontStrike extends PhysicalStrike {
private int getGlyphImageMinX(long ptr, int origMinX) {
int width = StrikeCache.getGlyphWidth(ptr);
byte format = StrikeCache.getGlyphFormat(ptr);
if (format != StrikeCache.PIXEL_FORMAT_LCD) return origMinX;
int height = StrikeCache.getGlyphHeight(ptr);
int rowBytes = StrikeCache.getGlyphRowBytes(ptr);
if (rowBytes == width) {
return origMinX;
}
if (StrikeCache.getGlyphImagePtr(ptr) == 0L) {
return origMinX;
}

View File

@@ -479,13 +479,19 @@ public final class GlyphList {
}
public static boolean canContainColorGlyphs() {
return FontUtilities.isMacOSX || FontUtilities.isLinux;
return true;
}
/**
* @return {@link StrikeCache#PIXEL_FORMAT_GREYSCALE} for greyscale,
* {@link StrikeCache#PIXEL_FORMAT_LCD} for LCD and {@link StrikeCache#PIXEL_FORMAT_BGRA} for BGRA glyph
*/
public byte getPixelFormat(int glyphIndex) {
return StrikeCache.getGlyphFormat(images[glyphIndex]);
}
public boolean isColorGlyph(int glyphIndex) {
int width = StrikeCache.getGlyphWidth(images[glyphIndex]);
int rowBytes = StrikeCache.getGlyphRowBytes(images[glyphIndex]);
return rowBytes == width * 4;
return getPixelFormat(glyphIndex) == StrikeCache.PIXEL_FORMAT_BGRA;
}
public SurfaceData getColorGlyphData() {

View File

@@ -27,6 +27,7 @@ package sun.font;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.lang.annotation.Native;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
@@ -121,9 +122,10 @@ public final class StrikeCache {
JAVA_CHAR.withName("height"), // 10+2=12
JAVA_CHAR.withName("rowBytes"), // 12+2=14
JAVA_BYTE.withName("managed"), // 14+1=15
JAVA_BYTE.withName("subpixelResolutionX"), // 15+1=16
JAVA_BYTE.withName("subpixelResolutionY"), // 16+1=17
MemoryLayout.paddingLayout(3), // 17+3=20
JAVA_BYTE.withName("format"), // 15+1=16
JAVA_BYTE.withName("subpixelResolutionX"), // 16+1=17
JAVA_BYTE.withName("subpixelResolutionY"), // 17+1=18
MemoryLayout.paddingLayout(2), // 18+2=20
JAVA_FLOAT.withName("topLeftX"), // 20+4=24
JAVA_FLOAT.withName("topLeftY"), // 24+4=28
MemoryLayout.paddingLayout(4), // 28+4=32
@@ -131,6 +133,11 @@ public final class StrikeCache {
ADDRESS.withName("image") // 40+8=48
);
@Native public static final byte PIXEL_FORMAT_UNKNOWN = -1;
@Native public static final byte PIXEL_FORMAT_GREYSCALE = 1;
@Native public static final byte PIXEL_FORMAT_LCD = 3;
@Native public static final byte PIXEL_FORMAT_BGRA = 4;
private static final long GLYPHIMAGESIZE = GlyphImageLayout.byteSize();
private static VarHandle getVarHandle(StructLayout struct, String name) {
@@ -145,6 +152,7 @@ public final class StrikeCache {
private static final VarHandle heightHandle = getVarHandle(GlyphImageLayout, "height");
private static final VarHandle rowBytesHandle = getVarHandle(GlyphImageLayout, "rowBytes");
private static final VarHandle managedHandle = getVarHandle(GlyphImageLayout, "managed");
private static final VarHandle formatHandle = getVarHandle(GlyphImageLayout, "format");
private static final VarHandle subpixelResolutionXHandle = getVarHandle(GlyphImageLayout, "subpixelResolutionX");
private static final VarHandle subpixelResolutionYHandle = getVarHandle(GlyphImageLayout, "subpixelResolutionY");
private static final VarHandle topLeftXHandle = getVarHandle(GlyphImageLayout, "topLeftX");
@@ -208,6 +216,13 @@ public final class StrikeCache {
return (byte)managedHandle.get(seg);
}
@SuppressWarnings("restricted")
static final byte getGlyphFormat(long ptr) {
MemorySegment seg = MemorySegment.ofAddress(ptr);
seg = seg.reinterpret(GLYPHIMAGESIZE);
return (byte)formatHandle.get(seg);
}
@SuppressWarnings("restricted")
static final byte getGlyphSubpixelResolutionX(long ptr) {
MemorySegment seg = MemorySegment.ofAddress(ptr);

View File

@@ -93,6 +93,7 @@ public class TrueTypeFont extends FileFont {
public static final int v1ttTag = 0x00010000; // 'v1tt' - Version 1 TT font
public static final int trueTag = 0x74727565; // 'true' - Version 2 TT font
public static final int ottoTag = 0x4f54544f; // 'otto' - OpenType font
public static final int COLRTag = 0x434f4c52; // 'COLR'
/* -- ID's used in the 'name' table */
public static final int MAC_PLATFORM_ID = 1;
@@ -865,6 +866,10 @@ public class TrueTypeFont extends FileFont {
return null;
}
boolean hasCOLRTable() {
return getDirectoryEntry(COLRTag) != null;
}
/* Used to determine if this size has embedded bitmaps, which
* for CJK fonts should be used in preference to LCD glyphs.
*/

View File

@@ -26,6 +26,7 @@
package sun.java2d.pipe;
import sun.awt.SunHints;
import sun.font.StrikeCache;
import sun.java2d.SunGraphics2D;
import sun.font.GlyphList;
@@ -41,50 +42,49 @@ public abstract class GlyphListLoopPipe extends GlyphListPipe
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl,
int aaHint) {
int prevLimit = 0;
boolean isColor = false;
byte pixelFormat = StrikeCache.PIXEL_FORMAT_UNKNOWN;
int len = gl.getNumGlyphs();
gl.startGlyphIteration();
if (GlyphList.canContainColorGlyphs()) {
for (int i = 0; i < len; i++) {
boolean newIsColor = gl.isColorGlyph(i);
if (newIsColor != isColor) {
drawGlyphListSegment(sg2d, gl, prevLimit, i, aaHint,
isColor);
byte newFormat = gl.getPixelFormat(i);
if (newFormat != pixelFormat) {
drawGlyphListSegment(sg2d, gl,
prevLimit, i, aaHint, pixelFormat);
prevLimit = i;
isColor = newIsColor;
pixelFormat = newFormat;
}
}
}
drawGlyphListSegment(sg2d, gl, prevLimit, len, aaHint, isColor);
drawGlyphListSegment(sg2d, gl, prevLimit, len, aaHint, pixelFormat);
}
private void drawGlyphListSegment(SunGraphics2D sg2d, GlyphList gl,
int fromglyph, int toGlyph,
int aaHint, boolean isColor) {
int aaHint, byte pixelFormat) {
if (fromglyph >= toGlyph) return;
if (isColor) {
sg2d.loops.drawGlyphListColorLoop.
DrawGlyphListColor(sg2d, sg2d.surfaceData,
gl, fromglyph, toGlyph);
} else {
switch (aaHint) {
case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
switch (pixelFormat) {
case StrikeCache.PIXEL_FORMAT_GREYSCALE:
if (aaHint == SunHints.INTVAL_TEXT_ANTIALIAS_OFF) {
sg2d.loops.drawGlyphListLoop.
DrawGlyphList(sg2d, sg2d.surfaceData,
gl, fromglyph, toGlyph);
return;
case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
} else {
sg2d.loops.drawGlyphListAALoop.
DrawGlyphListAA(sg2d, sg2d.surfaceData,
gl, fromglyph, toGlyph);
return;
case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
sg2d.loops.drawGlyphListLCDLoop.
DrawGlyphListLCD(sg2d, sg2d.surfaceData,
gl, fromglyph, toGlyph);
return;
}
}
return;
case StrikeCache.PIXEL_FORMAT_LCD:
sg2d.loops.drawGlyphListLCDLoop.
DrawGlyphListLCD(sg2d, sg2d.surfaceData,
gl, fromglyph, toGlyph);
return;
case StrikeCache.PIXEL_FORMAT_BGRA:
sg2d.loops.drawGlyphListColorLoop.
DrawGlyphListColor(sg2d, sg2d.surfaceData,
gl, fromglyph, toGlyph);
return;
}
}
}

View File

@@ -27,6 +27,7 @@
#define FontScalerDefsIncludesDefined
#include "AccelGlyphCache.h"
#include "sun_font_StrikeCache.h"
#ifdef __cplusplus
extern "C" {
@@ -74,7 +75,8 @@ typedef struct GlyphInfo {
UInt16 width;
UInt16 height;
UInt16 rowBytes;
UInt8 managed;
UInt8 managed;
UInt8 format; // sun_font_StrikeCache_PIXEL_FORMAT_*
UInt8 subpixelResolutionX;
UInt8 subpixelResolutionY;
float topLeftX;

View File

@@ -1306,7 +1306,7 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
continue;
}
if (ginfo->rowBytes == ginfo->width) {
if (ginfo->format == sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE) {
if (oglc->grayRenderHints == NULL) {
OGLContext_InitGrayRenderHints(env, oglc);
}
@@ -1326,7 +1326,7 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
} else {
ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y, subimage);
}
} else if (ginfo->rowBytes == ginfo->width * 4) {
} else if (ginfo->format == sun_font_StrikeCache_PIXEL_FORMAT_BGRA) {
// color glyph data
ok = OGLTR_DrawColorGlyphNoCache(oglc, ginfo, x, y);
} else {

View File

@@ -578,8 +578,7 @@ GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist,
free(gbv);
return (GlyphBlitVector*)NULL;
}
/* rowBytes==width tests if its a B&W or LCD glyph */
if (ginfo->width == ginfo->rowBytes) {
if (ginfo->format != sun_font_StrikeCache_PIXEL_FORMAT_LCD) {
subPixPos = JNI_FALSE;
}
}

View File

@@ -146,6 +146,7 @@ typedef struct FTScalerContext {
int ptsz; /* size in points */
int fixedSizeIndex;/* -1 for scalable fonts and index inside
* scalerInfo->face->available_sizes otherwise */
jboolean colorFont;
} FTScalerContext;
/* SampledBGRABitmap contains (possibly) downscaled image data
@@ -894,10 +895,10 @@ static void setupTransform(FT_Matrix* target, FTScalerContext *context) {
}
static void setDefaultScalerSettings(FTScalerContext *context) {
if (context->aaType == TEXT_AA_OFF) {
context->loadFlags = FT_LOAD_TARGET_MONO;
} else if (context->aaType == TEXT_AA_ON) {
if (context->aaType == TEXT_AA_ON || context->colorFont) {
context->loadFlags = FT_LOAD_TARGET_NORMAL;
} else if (context->aaType == TEXT_AA_OFF) {
context->loadFlags = FT_LOAD_TARGET_MONO;
} else {
context->lcdFilter = FT_LCD_FILTER_LIGHT;
if (context->aaType == TEXT_AA_LCD_HRGB ||
@@ -923,11 +924,13 @@ static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo,
FT_UInt dpi = (FT_UInt) getScreenResolution(env);
if (FT_IS_SCALABLE(scalerInfo->face)) { // Standard scalable face
context->colorFont = FT_HAS_COLOR(scalerInfo->face) ? TRUE : FALSE;
context->fixedSizeIndex = -1;
errCode = FT_Set_Char_Size(scalerInfo->face, 0,
ADJUST_FONT_SIZE(context->ptsz, dpi),
dpi, dpi);
} else { // Non-scalable face (that should only be bitmap faces)
context->colorFont = TRUE;
const int ptsz = context->ptsz;
// Best size is smallest, but not smaller than requested
int bestSizeIndex = 0;
@@ -1064,16 +1067,10 @@ static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo,
if (logFC && fcAutohintSet) fprintf(stderr, "FC_AUTOHINT(%d) ", fcAutohint);
if (context->aaType == TEXT_AA_ON) { // Greyscale AA
if (context->aaType == TEXT_AA_ON || context->colorFont) { // Greyscale AA or color glyph
setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet, FT_LOAD_DEFAULT, FT_RENDER_MODE_NORMAL);
} else if (context->aaType == TEXT_AA_OFF) { // No AA
/* We disable MONO for non-scalable fonts, because that
* is most probably a colored bitmap glyph */
setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet,
context->fixedSizeIndex == -1 ?
FT_LOAD_TARGET_MONO : FT_LOAD_TARGET_NORMAL,
context->fixedSizeIndex == -1 ?
FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL);
setupLoadRenderFlags(context, fcHintStyle, fcAutohint, fcAutohintSet, FT_LOAD_TARGET_MONO, FT_RENDER_MODE_MONO);
} else {
int fcRGBA = FC_RGBA_UNKNOWN;
if (fcAntialiasSet && fcAntialias) {
@@ -1112,10 +1109,6 @@ static int setupFTContext(JNIEnv *env, jobject font2D, FTScalerInfo *scalerInfo,
}
}
}
if (context->fixedSizeIndex != -1) {
// This is most probably a colored bitmap glyph, so enable COLOR
context->loadFlags |= FT_LOAD_COLOR;
}
FT_LcdFilter fcLCDFilter;
FcBool fcLCDFilterSet = (*FcPatternGetIntegerPtr)(pattern, FC_LCD_FILTER, 0, (int*) &fcLCDFilter) == FcResultMatch;
@@ -1731,9 +1724,12 @@ static jlong
context->loadFlags |= FT_LOAD_NO_HINTING;
}
/* Don't disable bitmaps when working with fixed-size glyph,
* this is most probably a BGRA glyph */
if (!context->useSbits && context->fixedSizeIndex == -1) {
if (context->colorFont) {
context->loadFlags |= FT_LOAD_COLOR;
}
/* Don't disable bitmaps for color glyphs */
if (!context->useSbits && !context->colorFont) {
context->loadFlags |= FT_LOAD_NO_BITMAP;
}
@@ -1743,10 +1739,10 @@ static jlong
Or we can disable hinting. */
/* select appropriate hinting mode */
if (context->aaType == TEXT_AA_OFF) {
target = FT_LOAD_TARGET_MONO;
} else if (context->aaType == TEXT_AA_ON) {
if (context->aaType == TEXT_AA_ON || context->colorFont) {
target = FT_LOAD_TARGET_NORMAL;
} else if (context->aaType == TEXT_AA_OFF) {
target = FT_LOAD_TARGET_MONO;
} else if (context->aaType == TEXT_AA_LCD_HRGB ||
context->aaType == TEXT_AA_LCD_HBGR) {
target = FT_LOAD_TARGET_LCD;
@@ -1771,7 +1767,7 @@ static jlong
int outlineGlyph = ftglyph->format == FT_GLYPH_FORMAT_OUTLINE;
/* apply styles */
if (context->doBold && outlineGlyph) { /* if bold style */
if (context->doBold && outlineGlyph && !context->colorFont) { /* if bold style */
GlyphSlot_Embolden(ftglyph, context->transform);
}
@@ -1786,7 +1782,7 @@ static jlong
* We do this by rendering the glyph multiple times with
* different subpixel offsets, which results in
* subpixelResolutionX * subpixelResolutionY images per glyph. */
if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY &&
if (!context->colorFont && ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY &&
context->aaType == TEXT_AA_ON && context->fmType == TEXT_FM_ON) {
subpixelResolutionX = subpixelGlyphResolution.x;
subpixelResolutionY = subpixelGlyphResolution.y;
@@ -1872,6 +1868,11 @@ static jlong
glyphInfo->subpixelResolutionX = subpixelResolutionX;
glyphInfo->subpixelResolutionY = subpixelResolutionY;
if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) glyphInfo->format = sun_font_StrikeCache_PIXEL_FORMAT_BGRA;
else if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD ||
ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) glyphInfo->format = sun_font_StrikeCache_PIXEL_FORMAT_LCD;
else glyphInfo->format = sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE;
if (renderImage) {
if (ftglyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD && width > 0) {
glyphInfo->width = width/3;

View File

@@ -192,13 +192,11 @@ public class XRGlyphCacheEntry {
}
public Type getType() {
int rowBytes = getSourceRowBytes();
int width = getWidth();
// 0x0 -> LCD is just for backward compatibiity
if (width == 0 || getHeight() == 0) return Type.LCD;
if (width == rowBytes) return Type.GRAYSCALE;
if (width * 4 == rowBytes) return Type.BGRA;
return Type.LCD;
byte format = StrikeCache.getGlyphFormat(glyphInfoPtr);
if (format == StrikeCache.PIXEL_FORMAT_GREYSCALE) return Type.GRAYSCALE;
else if (format == StrikeCache.PIXEL_FORMAT_LCD) return Type.LCD;
else if (format == StrikeCache.PIXEL_FORMAT_BGRA) return Type.BGRA;
else throw new IllegalStateException("Unknown glyph format: " + format);
}
public int getPaddedWidth() {

View File

@@ -287,6 +287,9 @@ JNIEXPORT jlong JNICALL AWTFontGenerateImage(AWTFont pFont, AWTChar2b* xChar) {
glyphInfo->cellInfo = NULL;
glyphInfo->width = width;
glyphInfo->height = height;
glyphInfo->subpixelResolutionX = 1;
glyphInfo->subpixelResolutionY = 1;
glyphInfo->format = sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE;
glyphInfo->topLeftX = xcs.lbearing;
glyphInfo->topLeftY = -xcs.ascent;
glyphInfo->advanceX = xcs.width;

View File

@@ -792,7 +792,7 @@ D3DTR_DrawGlyphList(D3DContext *d3dc, D3DSDOps *dstOps,
break;
}
grayscale = (ginfo->rowBytes == ginfo->width);
grayscale = (ginfo->format == sun_font_StrikeCache_PIXEL_FORMAT_GREYSCALE);
if (usePositions) {
jfloat posx = NEXT_FLOAT(positions);

View File

@@ -438,6 +438,9 @@ Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
glyphInfo->width -= 1; // must subtract 1
}
glyphInfo->height = height;
glyphInfo->subpixelResolutionX = 1;
glyphInfo->subpixelResolutionY = 1;
glyphInfo->format = sun_font_StrikeCache_PIXEL_FORMAT_LCD;
glyphInfo->advanceX = advanceX;
glyphInfo->advanceY = advanceY;
glyphInfo->topLeftX = (float)(topLeftX-1);

View File

@@ -264,6 +264,9 @@ Java_sun_font_FileFontStrike__1getGlyphImageFromWindowsUsingDirectWrite
glyphInfo->rowBytes = glyphBytesWidth;
glyphInfo->width = glyphWidth;
glyphInfo->height = glyphHeight;
glyphInfo->subpixelResolutionX = 1;
glyphInfo->subpixelResolutionY = 1;
glyphInfo->format = sun_font_StrikeCache_PIXEL_FORMAT_LCD;
glyphInfo->advanceX = rotation == 0 ? advance : rotation == 2 ? -advance : 0;
glyphInfo->advanceY = rotation == 3 ? advance : rotation == 1 ? -advance : 0;
glyphInfo->topLeftX = bbRect.left - xTransformed;