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"
|
#include "gfxPlatform.h"
|
||||||
|
|
||||||
#ifdef XP_MACOSX
|
|
||||||
# include "mozilla/gfx/ScaledFontMac.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace mozilla::gfx {
|
namespace mozilla::gfx {
|
||||||
|
|
||||||
BackingTexture::BackingTexture(const IntSize& aSize, SurfaceFormat aFormat,
|
BackingTexture::BackingTexture(const IntSize& aSize, SurfaceFormat aFormat,
|
||||||
@@ -4182,43 +4178,6 @@ static bool CheckForColorGlyphs(const RefPtr<SourceSurface>& aSurface) {
|
|||||||
return false;
|
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
|
// 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
|
// the text run that can be subsequently reused to quickly render the text run
|
||||||
// without using any software surfaces.
|
// without using any software surfaces.
|
||||||
@@ -4250,24 +4209,18 @@ bool SharedContextWebgl::DrawGlyphsAccel(ScaledFont* aFont,
|
|||||||
DeviceColor color = aOptions.mCompositionOp == CompositionOp::OP_CLEAR
|
DeviceColor color = aOptions.mCompositionOp == CompositionOp::OP_CLEAR
|
||||||
? DeviceColor(1, 1, 1, 1)
|
? DeviceColor(1, 1, 1, 1)
|
||||||
: static_cast<const ColorPattern&>(aPattern).mColor;
|
: 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
|
#ifdef XP_MACOSX
|
||||||
// If font smoothing is requested, even if there is no subpixel AA, gamma-
|
// On macOS, depending on whether the text is classified as light-on-dark or
|
||||||
// aware blending might be used and differing amounts of dilation might be
|
// dark-on-light, we may end up with different amounts of dilation applied, so
|
||||||
// applied.
|
// we can't use the same mask in the two circumstances, or the glyphs will be
|
||||||
if (aFont->GetType() == FontType::MAC &&
|
// dilated incorrectly.
|
||||||
static_cast<ScaledFontMac*>(aFont)->UseFontSmoothing()) {
|
bool lightOnDark =
|
||||||
usePreblend = true;
|
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
|
#endif
|
||||||
|
|
||||||
// If the font has bitmaps, use the color directly. Otherwise, the texture
|
// 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
|
// will hold a grayscale mask, so encode the key's subpixel and light-or-dark
|
||||||
// state in the color.
|
// state in the color.
|
||||||
@@ -4278,9 +4231,9 @@ bool SharedContextWebgl::DrawGlyphsAccel(ScaledFont* aFont,
|
|||||||
HashNumber hash =
|
HashNumber hash =
|
||||||
GlyphCacheEntry::HashGlyphs(aBuffer, quantizeTransform, quantizeScale);
|
GlyphCacheEntry::HashGlyphs(aBuffer, quantizeTransform, quantizeScale);
|
||||||
DeviceColor colorOrMask =
|
DeviceColor colorOrMask =
|
||||||
useBitmaps ? color
|
useBitmaps
|
||||||
: (usePreblend ? QuantizePreblendColor(color, aUseSubpixelAA)
|
? color
|
||||||
: DeviceColor::Mask(aUseSubpixelAA ? 1 : 0, 1));
|
: DeviceColor::Mask(aUseSubpixelAA ? 1 : 0, lightOnDark ? 1 : 0);
|
||||||
IntRect clipRect(IntPoint(), mViewportSize);
|
IntRect clipRect(IntPoint(), mViewportSize);
|
||||||
RefPtr<GlyphCacheEntry> entry =
|
RefPtr<GlyphCacheEntry> entry =
|
||||||
cache->FindEntry(aBuffer, colorOrMask, quantizeTransform, quantizeScale,
|
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.
|
// wasn't valid. Render the text run into a temporary target.
|
||||||
RefPtr<DrawTargetSkia> textDT = new DrawTargetSkia;
|
RefPtr<DrawTargetSkia> textDT = new DrawTargetSkia;
|
||||||
if (textDT->Init(intBounds.Size(),
|
if (textDT->Init(intBounds.Size(),
|
||||||
useBitmaps || usePreblend || aUseSubpixelAA
|
lightOnDark && !useBitmaps && !aUseSubpixelAA
|
||||||
? SurfaceFormat::B8G8R8A8
|
? SurfaceFormat::A8
|
||||||
: 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 *
|
textDT->SetTransform(currentTransform *
|
||||||
Matrix::Translation(-intBounds.TopLeft()));
|
Matrix::Translation(-intBounds.TopLeft()));
|
||||||
textDT->SetPermitSubpixelAA(aUseSubpixelAA);
|
textDT->SetPermitSubpixelAA(aUseSubpixelAA);
|
||||||
@@ -4359,20 +4319,42 @@ bool SharedContextWebgl::DrawGlyphsAccel(ScaledFont* aFont,
|
|||||||
aOptions.mAntialiasMode);
|
aOptions.mAntialiasMode);
|
||||||
// If bitmaps might be used, then we have to supply the color, as color
|
// 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
|
// 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
|
// know ahead of time. Otherwise, assume the output will be a mask and
|
||||||
// output also will depend on the supplied color. Otherwise, assume the
|
// just render it white to determine intensity. Depending on whether the
|
||||||
// output will be a mask and just render it white to determine intensity.
|
// text is light or dark, we render white or black text respectively.
|
||||||
if (!useBitmaps && usePreblend) {
|
ColorPattern colorPattern(
|
||||||
textDT->DrawGlyphMask(aFont, aBuffer, color, aStrokeOptions,
|
useBitmaps ? color : DeviceColor::Mask(lightOnDark ? 1 : 0, 1));
|
||||||
drawOptions);
|
|
||||||
} else {
|
|
||||||
ColorPattern colorPattern(useBitmaps ? color : DeviceColor(1, 1, 1, 1));
|
|
||||||
if (aStrokeOptions) {
|
if (aStrokeOptions) {
|
||||||
textDT->StrokeGlyphs(aFont, aBuffer, colorPattern, *aStrokeOptions,
|
textDT->StrokeGlyphs(aFont, aBuffer, colorPattern, *aStrokeOptions,
|
||||||
drawOptions);
|
drawOptions);
|
||||||
} else {
|
} 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();
|
RefPtr<SourceSurface> textSurface = textDT->Snapshot();
|
||||||
if (textSurface) {
|
if (textSurface) {
|
||||||
|
|||||||
@@ -24,10 +24,6 @@
|
|||||||
#include "skia/include/core/SkRegion.h"
|
#include "skia/include/core/SkRegion.h"
|
||||||
#include "skia/include/effects/SkImageFilters.h"
|
#include "skia/include/effects/SkImageFilters.h"
|
||||||
#include "skia/include/private/base/SkMalloc.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 "Blur.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "Tools.h"
|
#include "Tools.h"
|
||||||
@@ -1256,8 +1252,7 @@ static bool CanDrawFont(ScaledFont* aFont) {
|
|||||||
void DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
void DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
||||||
const Pattern& aPattern,
|
const Pattern& aPattern,
|
||||||
const StrokeOptions* aStrokeOptions,
|
const StrokeOptions* aStrokeOptions,
|
||||||
const DrawOptions& aOptions,
|
const DrawOptions& aOptions) {
|
||||||
SkShader* aShader) {
|
|
||||||
if (!CanDrawFont(aFont)) {
|
if (!CanDrawFont(aFont)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1293,10 +1288,6 @@ void DrawTargetSkia::DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
|||||||
|
|
||||||
skiaFont->SetupSkFontDrawOptions(font);
|
skiaFont->SetupSkFontDrawOptions(font);
|
||||||
|
|
||||||
if (aShader) {
|
|
||||||
paint.mPaint.setShader(sk_ref_sp(aShader));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit the amount of internal batch allocations Skia does.
|
// Limit the amount of internal batch allocations Skia does.
|
||||||
const uint32_t kMaxGlyphBatchSize = 8192;
|
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(
|
Maybe<Rect> DrawTargetSkia::GetGlyphLocalBounds(
|
||||||
ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern,
|
ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern,
|
||||||
const StrokeOptions* aStrokeOptions, const DrawOptions& aOptions) {
|
const StrokeOptions* aStrokeOptions, const DrawOptions& aOptions) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
class SkCanvas;
|
class SkCanvas;
|
||||||
class SkShader;
|
|
||||||
class SkSurface;
|
class SkSurface;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
@@ -163,11 +162,6 @@ class DrawTargetSkia : public DrawTarget {
|
|||||||
const StrokeOptions* aStrokeOptions,
|
const StrokeOptions* aStrokeOptions,
|
||||||
const DrawOptions& aOptions);
|
const DrawOptions& aOptions);
|
||||||
|
|
||||||
void DrawGlyphMask(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
|
||||||
const DeviceColor& aColor,
|
|
||||||
const StrokeOptions* aStrokeOptions = nullptr,
|
|
||||||
const DrawOptions& aOptions = DrawOptions());
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SourceSurfaceSkia;
|
friend class SourceSurfaceSkia;
|
||||||
|
|
||||||
@@ -178,8 +172,7 @@ class DrawTargetSkia : public DrawTarget {
|
|||||||
void DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
void DrawGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
|
||||||
const Pattern& aPattern,
|
const Pattern& aPattern,
|
||||||
const StrokeOptions* aStrokeOptions = nullptr,
|
const StrokeOptions* aStrokeOptions = nullptr,
|
||||||
const DrawOptions& aOptions = DrawOptions(),
|
const DrawOptions& aOptions = DrawOptions());
|
||||||
SkShader* aShader = nullptr);
|
|
||||||
|
|
||||||
struct PushedLayer {
|
struct PushedLayer {
|
||||||
PushedLayer(bool aOldPermitSubpixelAA, SourceSurface* aMask)
|
PushedLayer(bool aOldPermitSubpixelAA, SourceSurface* aMask)
|
||||||
|
|||||||
@@ -62,8 +62,6 @@ class ScaledFontMac : public ScaledFontBase {
|
|||||||
|
|
||||||
bool UseSubpixelPosition() const override { return true; }
|
bool UseSubpixelPosition() const override { return true; }
|
||||||
|
|
||||||
bool UseFontSmoothing() const { return mUseFontSmoothing; }
|
|
||||||
|
|
||||||
cairo_font_face_t* CreateCairoFontFace(
|
cairo_font_face_t* CreateCairoFontFace(
|
||||||
cairo_font_options_t* aFontOptions) override;
|
cairo_font_options_t* aFontOptions) override;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user