Backed out changeset 0ac3aa2e9c97 (bug 1910869) for causing failures at 2d.text.draw.generic.family.w.html. CLOSED TREE

This commit is contained in:
Butkovits Atila
2024-08-15 21:23:02 +03:00
parent 45233a15e8
commit 994dddfcd9
4 changed files with 59 additions and 140 deletions

View File

@@ -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) {