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);
} else {
ColorPattern colorPattern(useBitmaps ? color : DeviceColor(1, 1, 1, 1));
// 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 {
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) {

View File

@@ -24,10 +24,6 @@
#include "skia/include/core/SkRegion.h"
#include "skia/include/effects/SkImageFilters.h"
#include "skia/include/private/base/SkMalloc.h"
#include "skia/src/core/SkEffectPriv.h"
#include "skia/src/core/SkRasterPipeline.h"
#include "skia/src/core/SkWriteBuffer.h"
#include "skia/src/shaders/SkEmptyShader.h"
#include "Blur.h"
#include "Logging.h"
#include "Tools.h"
@@ -1256,8 +1252,7 @@ static bool CanDrawFont(ScaledFont* aFont) {
void DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
const Pattern& aPattern,
const StrokeOptions* aStrokeOptions,
const DrawOptions& aOptions,
SkShader* aShader) {
const DrawOptions& aOptions) {
if (!CanDrawFont(aFont)) {
return;
}
@@ -1293,10 +1288,6 @@ void DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
skiaFont->SetupSkFontDrawOptions(font);
if (aShader) {
paint.mPaint.setShader(sk_ref_sp(aShader));
}
// Limit the amount of internal batch allocations Skia does.
const uint32_t kMaxGlyphBatchSize = 8192;
@@ -1315,51 +1306,6 @@ void DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
}
}
// This shader overrides the luminance color used to generate the preblend
// tables for glyphs, without actually changing the rasterized color. This is
// necesary for subpixel AA blending which requires both the mask and color
// as separate inputs.
class GlyphMaskShader : public SkEmptyShader {
public:
explicit GlyphMaskShader(const DeviceColor& aColor)
: mColor({aColor.r, aColor.g, aColor.b, aColor.a}) {}
bool onAsLuminanceColor(SkColor4f* aLum) const override {
*aLum = mColor;
return true;
}
bool isOpaque() const override { return true; }
bool isConstant() const override { return true; }
void flatten(SkWriteBuffer& buffer) const override {
buffer.writeColor4f(mColor);
}
bool appendStages(const SkStageRec& rec,
const SkShaders::MatrixRec&) const override {
rec.fPipeline->appendConstantColor(rec.fAlloc,
SkColor4f{1, 1, 1, 1}.premul().vec());
return true;
}
private:
SkColor4f mColor;
};
void DrawTargetSkia::DrawGlyphMask(ScaledFont* aFont,
const GlyphBuffer& aBuffer,
const DeviceColor& aColor,
const StrokeOptions* aStrokeOptions,
const DrawOptions& aOptions) {
// Draw a mask using the GlyphMaskShader that can be used for subpixel AA
// but that uses the gamma preblend weighting of the given color, even though
// the mask itself does not use that color.
sk_sp<GlyphMaskShader> shader = sk_make_sp<GlyphMaskShader>(aColor);
DrawGlyphs(aFont, aBuffer, ColorPattern(DeviceColor(1, 1, 1, 1)),
aStrokeOptions, aOptions, shader.get());
}
Maybe<Rect> DrawTargetSkia::GetGlyphLocalBounds(
ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern,
const StrokeOptions* aStrokeOptions, const DrawOptions& aOptions) {

View File

@@ -16,7 +16,6 @@
#endif
class SkCanvas;
class SkShader;
class SkSurface;
namespace mozilla {
@@ -163,11 +162,6 @@ class DrawTargetSkia : public DrawTarget {
const StrokeOptions* aStrokeOptions,
const DrawOptions& aOptions);
void DrawGlyphMask(ScaledFont* aFont, const GlyphBuffer& aBuffer,
const DeviceColor& aColor,
const StrokeOptions* aStrokeOptions = nullptr,
const DrawOptions& aOptions = DrawOptions());
private:
friend class SourceSurfaceSkia;
@@ -178,8 +172,7 @@ class DrawTargetSkia : public DrawTarget {
void DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
const Pattern& aPattern,
const StrokeOptions* aStrokeOptions = nullptr,
const DrawOptions& aOptions = DrawOptions(),
SkShader* aShader = nullptr);
const DrawOptions& aOptions = DrawOptions());
struct PushedLayer {
PushedLayer(bool aOldPermitSubpixelAA, SourceSurface* aMask)

View File

@@ -62,8 +62,6 @@ class ScaledFontMac : public ScaledFontBase {
bool UseSubpixelPosition() const override { return true; }
bool UseFontSmoothing() const { return mUseFontSmoothing; }
cairo_font_face_t* CreateCairoFontFace(
cairo_font_options_t* aFontOptions) override;