Backed out changeset 0ac3aa2e9c97 (bug 1910869) for causing failures at 2d.text.draw.generic.family.w.html. CLOSED TREE
This commit is contained in:
@@ -37,10 +37,6 @@
|
||||
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
# include "mozilla/gfx/ScaledFontMac.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla::gfx {
|
||||
|
||||
BackingTexture::BackingTexture(const IntSize& aSize, SurfaceFormat aFormat,
|
||||
@@ -4182,43 +4178,6 @@ static bool CheckForColorGlyphs(const RefPtr<SourceSurface>& aSurface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Quantize the preblend color used to key the cache, as only the high bits are
|
||||
// used to determine the amount of preblending. This avoids excessive cache use.
|
||||
// This roughly matches the quantization used in WebRender and Skia.
|
||||
static DeviceColor QuantizePreblendColor(const DeviceColor& aColor,
|
||||
bool aUseSubpixelAA) {
|
||||
int32_t r = int32_t(aColor.r * 255.0f + 0.5f);
|
||||
int32_t g = int32_t(aColor.r * 255.0f + 0.5f);
|
||||
int32_t b = int32_t(aColor.r * 255.0f + 0.5f);
|
||||
// Ensure that even if two values would normally quantize to the same bucket,
|
||||
// that the reference value within the bucket still allows for accurate
|
||||
// determination of whether light-on-dark or dark-on-light rasterization will
|
||||
// be used (as on macOS).
|
||||
bool lightOnDark = r >= 85 && g >= 85 && b >= 85 && r + g + b >= 2 * 255;
|
||||
// Skia only uses the high 3 bits of each color component to cache preblend
|
||||
// ramp tables.
|
||||
constexpr int32_t lumBits = 3;
|
||||
constexpr int32_t ceilMask = (1 << (8 - lumBits)) - 1;
|
||||
constexpr int32_t floorMask = ((1 << lumBits) - 1) << (8 - lumBits);
|
||||
if (!aUseSubpixelAA) {
|
||||
// If not using subpixel AA, then quantize only the luminance, stored in the
|
||||
// G channel.
|
||||
g = (r * 54 + g * 183 + b * 19) >> 8;
|
||||
g |= ceilMask;
|
||||
// Still distinguish between light and dark in the key.
|
||||
r = b = lightOnDark ? 255 : 0;
|
||||
} else if (lightOnDark) {
|
||||
r |= ceilMask;
|
||||
g |= ceilMask;
|
||||
b |= ceilMask;
|
||||
} else {
|
||||
r &= floorMask;
|
||||
g &= floorMask;
|
||||
b &= floorMask;
|
||||
}
|
||||
return DeviceColor{r / 255.0f, g / 255.0f, b / 255.0f, 1.0f};
|
||||
}
|
||||
|
||||
// Draws glyphs to the WebGL target by trying to generate a cached texture for
|
||||
// the text run that can be subsequently reused to quickly render the text run
|
||||
// without using any software surfaces.
|
||||
@@ -4250,24 +4209,18 @@ bool SharedContextWebgl::DrawGlyphsAccel(ScaledFont* aFont,
|
||||
DeviceColor color = aOptions.mCompositionOp == CompositionOp::OP_CLEAR
|
||||
? DeviceColor(1, 1, 1, 1)
|
||||
: static_cast<const ColorPattern&>(aPattern).mColor;
|
||||
#if defined(XP_MACOSX) || defined(XP_WIN)
|
||||
// macOS and Windows use gamma-aware blending.
|
||||
bool usePreblend = aUseSubpixelAA;
|
||||
#else
|
||||
// FreeType backends currently don't use any preblending.
|
||||
bool usePreblend = false;
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// If font smoothing is requested, even if there is no subpixel AA, gamma-
|
||||
// aware blending might be used and differing amounts of dilation might be
|
||||
// applied.
|
||||
if (aFont->GetType() == FontType::MAC &&
|
||||
static_cast<ScaledFontMac*>(aFont)->UseFontSmoothing()) {
|
||||
usePreblend = true;
|
||||
}
|
||||
// On macOS, depending on whether the text is classified as light-on-dark or
|
||||
// dark-on-light, we may end up with different amounts of dilation applied, so
|
||||
// we can't use the same mask in the two circumstances, or the glyphs will be
|
||||
// dilated incorrectly.
|
||||
bool lightOnDark =
|
||||
useBitmaps || (color.r >= 0.33f && color.g >= 0.33f && color.b >= 0.33f &&
|
||||
color.r + color.g + color.b >= 2.0f);
|
||||
#else
|
||||
// On other platforms, we assume no color-dependent dilation.
|
||||
const bool lightOnDark = true;
|
||||
#endif
|
||||
|
||||
// If the font has bitmaps, use the color directly. Otherwise, the texture
|
||||
// will hold a grayscale mask, so encode the key's subpixel and light-or-dark
|
||||
// state in the color.
|
||||
@@ -4278,9 +4231,9 @@ bool SharedContextWebgl::DrawGlyphsAccel(ScaledFont* aFont,
|
||||
HashNumber hash =
|
||||
GlyphCacheEntry::HashGlyphs(aBuffer, quantizeTransform, quantizeScale);
|
||||
DeviceColor colorOrMask =
|
||||
useBitmaps ? color
|
||||
: (usePreblend ? QuantizePreblendColor(color, aUseSubpixelAA)
|
||||
: DeviceColor::Mask(aUseSubpixelAA ? 1 : 0, 1));
|
||||
useBitmaps
|
||||
? color
|
||||
: DeviceColor::Mask(aUseSubpixelAA ? 1 : 0, lightOnDark ? 1 : 0);
|
||||
IntRect clipRect(IntPoint(), mViewportSize);
|
||||
RefPtr<GlyphCacheEntry> entry =
|
||||
cache->FindEntry(aBuffer, colorOrMask, quantizeTransform, quantizeScale,
|
||||
@@ -4349,9 +4302,16 @@ bool SharedContextWebgl::DrawGlyphsAccel(ScaledFont* aFont,
|
||||
// wasn't valid. Render the text run into a temporary target.
|
||||
RefPtr<DrawTargetSkia> textDT = new DrawTargetSkia;
|
||||
if (textDT->Init(intBounds.Size(),
|
||||
useBitmaps || usePreblend || aUseSubpixelAA
|
||||
? SurfaceFormat::B8G8R8A8
|
||||
: SurfaceFormat::A8)) {
|
||||
lightOnDark && !useBitmaps && !aUseSubpixelAA
|
||||
? SurfaceFormat::A8
|
||||
: SurfaceFormat::B8G8R8A8)) {
|
||||
if (!lightOnDark) {
|
||||
// If rendering dark-on-light text, we need to clear the background to
|
||||
// white while using an opaque alpha value to allow this.
|
||||
textDT->FillRect(Rect(IntRect(IntPoint(), intBounds.Size())),
|
||||
ColorPattern(DeviceColor(1, 1, 1, 1)),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
}
|
||||
textDT->SetTransform(currentTransform *
|
||||
Matrix::Translation(-intBounds.TopLeft()));
|
||||
textDT->SetPermitSubpixelAA(aUseSubpixelAA);
|
||||
@@ -4359,20 +4319,42 @@ bool SharedContextWebgl::DrawGlyphsAccel(ScaledFont* aFont,
|
||||
aOptions.mAntialiasMode);
|
||||
// If bitmaps might be used, then we have to supply the color, as color
|
||||
// emoji may ignore it while grayscale bitmaps may use it, with no way to
|
||||
// know ahead of time. If we are using preblending in some form, then the
|
||||
// output also will depend on the supplied color. Otherwise, assume the
|
||||
// output will be a mask and just render it white to determine intensity.
|
||||
if (!useBitmaps && usePreblend) {
|
||||
textDT->DrawGlyphMask(aFont, aBuffer, color, aStrokeOptions,
|
||||
drawOptions);
|
||||
// know ahead of time. Otherwise, assume the output will be a mask and
|
||||
// just render it white to determine intensity. Depending on whether the
|
||||
// text is light or dark, we render white or black text respectively.
|
||||
ColorPattern colorPattern(
|
||||
useBitmaps ? color : DeviceColor::Mask(lightOnDark ? 1 : 0, 1));
|
||||
if (aStrokeOptions) {
|
||||
textDT->StrokeGlyphs(aFont, aBuffer, colorPattern, *aStrokeOptions,
|
||||
drawOptions);
|
||||
} else {
|
||||
ColorPattern colorPattern(useBitmaps ? color : DeviceColor(1, 1, 1, 1));
|
||||
if (aStrokeOptions) {
|
||||
textDT->StrokeGlyphs(aFont, aBuffer, colorPattern, *aStrokeOptions,
|
||||
drawOptions);
|
||||
} else {
|
||||
textDT->FillGlyphs(aFont, aBuffer, colorPattern, drawOptions);
|
||||
textDT->FillGlyphs(aFont, aBuffer, colorPattern, drawOptions);
|
||||
}
|
||||
if (!lightOnDark) {
|
||||
uint8_t* data = nullptr;
|
||||
IntSize size;
|
||||
int32_t stride = 0;
|
||||
SurfaceFormat format = SurfaceFormat::UNKNOWN;
|
||||
if (!textDT->LockBits(&data, &size, &stride, &format)) {
|
||||
return false;
|
||||
}
|
||||
uint8_t* row = data;
|
||||
for (int y = 0; y < size.height; ++y) {
|
||||
uint8_t* px = row;
|
||||
for (int x = 0; x < size.width; ++x) {
|
||||
// If rendering dark-on-light text, we need to invert the final mask
|
||||
// so that it is in the expected white text on transparent black
|
||||
// format. The alpha will be initialized to the largest of the
|
||||
// values.
|
||||
px[0] = 255 - px[0];
|
||||
px[1] = 255 - px[1];
|
||||
px[2] = 255 - px[2];
|
||||
px[3] = std::max(px[0], std::max(px[1], px[2]));
|
||||
px += 4;
|
||||
}
|
||||
row += stride;
|
||||
}
|
||||
textDT->ReleaseBits(data);
|
||||
}
|
||||
RefPtr<SourceSurface> textSurface = textDT->Snapshot();
|
||||
if (textSurface) {
|
||||
|
||||
Reference in New Issue
Block a user