зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1740530 - patch 4 - Use harfbuzz color-palette access functions, instead of rolling our own. r=gfx-reviewers,lsalzman
Depends on D152038 Differential Revision: https://phabricator.services.mozilla.com/D153870
This commit is contained in:
Родитель
15a732fbb5
Коммит
6012755291
|
@ -7,6 +7,7 @@
|
|||
#include "gfxFontUtils.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "harfbuzz/hb-ot.h"
|
||||
#include "mozilla/gfx/Helpers.h"
|
||||
#include "TextDrawTarget.h"
|
||||
|
||||
|
@ -37,52 +38,31 @@ struct COLRHeader {
|
|||
}
|
||||
};
|
||||
|
||||
struct CPALHeaderVersion0 {
|
||||
AutoSwap_PRUint16 version;
|
||||
AutoSwap_PRUint16 numPaletteEntries;
|
||||
AutoSwap_PRUint16 numPalettes;
|
||||
AutoSwap_PRUint16 numColorRecords;
|
||||
AutoSwap_PRUint32 offsetFirstColorRecord;
|
||||
};
|
||||
|
||||
// sRGB color space
|
||||
struct CPALColorRecord {
|
||||
uint8_t blue;
|
||||
uint8_t green;
|
||||
uint8_t red;
|
||||
uint8_t alpha;
|
||||
};
|
||||
|
||||
struct PaintState {
|
||||
const COLRHeader* mHeader;
|
||||
const CPALColorRecord* mPalette;
|
||||
const hb_color_t* mPalette;
|
||||
DrawTarget* mDrawTarget;
|
||||
ScaledFont* mScaledFont;
|
||||
DrawOptions mDrawOptions;
|
||||
sRGBColor mCurrentColor;
|
||||
};
|
||||
uint16_t mNumColors;
|
||||
|
||||
static const CPALColorRecord* GetPaletteByIndex(hb_blob_t* aCPAL,
|
||||
uint32_t aIndex) {
|
||||
const auto* cpal = reinterpret_cast<const CPALHeaderVersion0*>(
|
||||
hb_blob_get_data(aCPAL, nullptr));
|
||||
const uint32_t offset = cpal->offsetFirstColorRecord;
|
||||
return reinterpret_cast<const CPALColorRecord*>(
|
||||
reinterpret_cast<const uint8_t*>(cpal) + offset);
|
||||
}
|
||||
|
||||
static DeviceColor DoGetColor(PaintState& aState, uint16_t aPaletteIndex,
|
||||
float aAlpha) {
|
||||
sRGBColor color;
|
||||
if (aPaletteIndex == 0xFFFF) {
|
||||
color = aState.mCurrentColor;
|
||||
} else {
|
||||
const CPALColorRecord& c = aState.mPalette[uint16_t(aPaletteIndex)];
|
||||
color = sRGBColor(c.red / 255.0, c.green / 255.0, c.blue / 255.0,
|
||||
c.alpha / 255.0 * aAlpha);
|
||||
DeviceColor GetColor(uint16_t aPaletteIndex, float aAlpha) {
|
||||
sRGBColor color;
|
||||
if (aPaletteIndex < mNumColors) {
|
||||
const hb_color_t& c = mPalette[uint16_t(aPaletteIndex)];
|
||||
color = sRGBColor(
|
||||
hb_color_get_red(c) / 255.0, hb_color_get_green(c) / 255.0,
|
||||
hb_color_get_blue(c) / 255.0, hb_color_get_alpha(c) / 255.0 * aAlpha);
|
||||
} else if (aPaletteIndex == 0xffff) {
|
||||
color = mCurrentColor;
|
||||
color.a *= aAlpha;
|
||||
} else { // Palette index out of range! Return transparent black.
|
||||
color = sRGBColor();
|
||||
}
|
||||
return ToDeviceColor(color);
|
||||
}
|
||||
return ToDeviceColor(color);
|
||||
}
|
||||
};
|
||||
|
||||
struct LayerRecord {
|
||||
AutoSwap_PRUint16 glyphId;
|
||||
|
@ -94,7 +74,7 @@ struct LayerRecord {
|
|||
GlyphBuffer buffer{&glyph, 1};
|
||||
aState.mDrawTarget->FillGlyphs(
|
||||
aState.mScaledFont, buffer,
|
||||
ColorPattern(DoGetColor(aState, paletteEntryIndex, aAlpha)),
|
||||
ColorPattern(aState.GetColor(paletteEntryIndex, aAlpha)),
|
||||
aState.mDrawOptions);
|
||||
return true;
|
||||
}
|
||||
|
@ -130,14 +110,68 @@ struct COLRBaseGlyphRecord {
|
|||
};
|
||||
|
||||
bool COLRFonts::ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL) {
|
||||
unsigned int colrLength;
|
||||
const COLRHeader* colr =
|
||||
reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR, &colrLength));
|
||||
struct ColorRecord {
|
||||
uint8_t blue;
|
||||
uint8_t green;
|
||||
uint8_t red;
|
||||
uint8_t alpha;
|
||||
};
|
||||
|
||||
struct CPALHeaderVersion0 {
|
||||
AutoSwap_PRUint16 version;
|
||||
AutoSwap_PRUint16 numPaletteEntries;
|
||||
AutoSwap_PRUint16 numPalettes;
|
||||
AutoSwap_PRUint16 numColorRecords;
|
||||
AutoSwap_PRUint32 colorRecordsArrayOffset;
|
||||
// uint16 colorRecordIndices[numPalettes];
|
||||
const AutoSwap_PRUint16* colorRecordIndices() const {
|
||||
return reinterpret_cast<const AutoSwap_PRUint16*>(this + 1);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int cpalLength;
|
||||
const CPALHeaderVersion0* cpal = reinterpret_cast<const CPALHeaderVersion0*>(
|
||||
hb_blob_get_data(aCPAL, &cpalLength));
|
||||
if (!cpal || cpalLength < sizeof(CPALHeaderVersion0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!colr || !cpal || !colrLength || !cpalLength) {
|
||||
// We can handle either version 0 or 1.
|
||||
if (uint16_t(cpal->version) > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint16_t numPaletteEntries = cpal->numPaletteEntries;
|
||||
const uint16_t numPalettes = cpal->numPalettes;
|
||||
const uint16_t numColorRecords = cpal->numColorRecords;
|
||||
const uint32_t colorRecordsArrayOffset = cpal->colorRecordsArrayOffset;
|
||||
const auto* indices = cpal->colorRecordIndices();
|
||||
|
||||
if (colorRecordsArrayOffset >= cpalLength) {
|
||||
return false;
|
||||
}
|
||||
if (!numPaletteEntries || !numPalettes ||
|
||||
numColorRecords < numPaletteEntries) {
|
||||
return false;
|
||||
}
|
||||
if (sizeof(ColorRecord) * numColorRecords >
|
||||
cpalLength - colorRecordsArrayOffset) {
|
||||
return false;
|
||||
}
|
||||
for (uint16_t i = 0; i < numPalettes; ++i) {
|
||||
uint32_t index = indices[i];
|
||||
if (index + numPaletteEntries > numColorRecords) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The additional fields in CPALv1 are not checked here; the harfbuzz code
|
||||
// handles reading them safely.
|
||||
|
||||
unsigned int colrLength;
|
||||
const COLRHeader* colr =
|
||||
reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR, &colrLength));
|
||||
if (!colr || colrLength < sizeof(COLRHeader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -151,10 +185,6 @@ bool COLRFonts::ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL) {
|
|||
const uint32_t offsetLayerRecord = colr->offsetLayerRecord;
|
||||
const uint16_t numLayerRecords = colr->numLayerRecords;
|
||||
|
||||
const uint32_t offsetFirstColorRecord = cpal->offsetFirstColorRecord;
|
||||
const uint16_t numColorRecords = cpal->numColorRecords;
|
||||
const uint32_t numPaletteEntries = cpal->numPaletteEntries;
|
||||
|
||||
if (offsetBaseGlyphRecord >= colrLength) {
|
||||
return false;
|
||||
}
|
||||
|
@ -163,14 +193,6 @@ bool COLRFonts::ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (offsetFirstColorRecord >= cpalLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!numPaletteEntries) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sizeof(COLRBaseGlyphRecord) * numBaseGlyphRecord >
|
||||
colrLength - offsetBaseGlyphRecord) {
|
||||
// COLR base glyph record will be overflow
|
||||
|
@ -182,17 +204,6 @@ bool COLRFonts::ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sizeof(CPALColorRecord) * numColorRecords >
|
||||
cpalLength - offsetFirstColorRecord) {
|
||||
// CPAL color record will be overflow
|
||||
return false;
|
||||
}
|
||||
|
||||
if (numPaletteEntries * uint16_t(cpal->numPalettes) != numColorRecords) {
|
||||
// palette of CPAL color record will be overflow.
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t lastGlyphId = 0;
|
||||
const COLRBaseGlyphRecord* baseGlyph =
|
||||
reinterpret_cast<const COLRBaseGlyphRecord*>(
|
||||
|
@ -258,7 +269,7 @@ const COLRBaseGlyphRecord* COLRFonts::GetGlyphLayers(hb_blob_t* aCOLR,
|
|||
}
|
||||
|
||||
bool COLRFonts::PaintGlyphLayers(
|
||||
hb_blob_t* aCOLR, hb_blob_t* aCPAL, const COLRBaseGlyphRecord* aLayers,
|
||||
hb_blob_t* aCOLR, hb_face_t* aFace, const COLRBaseGlyphRecord* aLayers,
|
||||
DrawTarget* aDrawTarget, layout::TextDrawTarget* aTextDrawer,
|
||||
ScaledFont* aScaledFont, DrawOptions aDrawOptions,
|
||||
const sRGBColor& aCurrentColor, const Point& aPoint) {
|
||||
|
@ -284,11 +295,24 @@ bool COLRFonts::PaintGlyphLayers(
|
|||
// might be wrapped in a shadow that uses the text run's glyphs.
|
||||
alpha = aCurrentColor.a;
|
||||
}
|
||||
auto* colr =
|
||||
|
||||
// Get the default palette (TODO: hook up CSS font-palette support)
|
||||
unsigned int colorCount = 0;
|
||||
AutoTArray<hb_color_t, 64> colors;
|
||||
colors.SetLength(hb_ot_color_palette_get_colors(aFace, /* paletteIndex */ 0,
|
||||
0, &colorCount, nullptr));
|
||||
colorCount = colors.Length();
|
||||
hb_ot_color_palette_get_colors(aFace, 0, 0, &colorCount, colors.Elements());
|
||||
|
||||
const COLRHeader* colr =
|
||||
reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR, nullptr));
|
||||
auto* palette = GetPaletteByIndex(aCPAL, 0); // TODO: font-palette support
|
||||
PaintState state{colr, palette, aDrawTarget,
|
||||
aScaledFont, aDrawOptions, aCurrentColor};
|
||||
PaintState state{colr,
|
||||
colors.Elements(),
|
||||
aDrawTarget,
|
||||
aScaledFont,
|
||||
aDrawOptions,
|
||||
aCurrentColor,
|
||||
uint16_t(colors.Length())};
|
||||
return aLayers->Paint(state, alpha, aPoint);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
struct hb_blob_t;
|
||||
struct hb_face_t;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -28,7 +29,7 @@ class COLRFonts {
|
|||
uint32_t aGlyphId);
|
||||
|
||||
static bool PaintGlyphLayers(
|
||||
hb_blob_t* aCOLR, hb_blob_t* aCPAL, const COLRBaseGlyphRecord* aLayers,
|
||||
hb_blob_t* aCOLR, hb_face_t* aFace, const COLRBaseGlyphRecord* aLayers,
|
||||
DrawTarget* aDrawTarget, layout::TextDrawTarget* aTextDrawer,
|
||||
ScaledFont* aScaledFont, DrawOptions aDrawOptions,
|
||||
const sRGBColor& aCurrentColor, const Point& aPoint);
|
||||
|
|
|
@ -2467,17 +2467,20 @@ bool gfxFont::RenderColorGlyph(DrawTarget* aDrawTarget, gfxContext* aContext,
|
|||
ScaledFont* aScaledFont,
|
||||
DrawOptions aDrawOptions, const Point& aPoint,
|
||||
uint32_t aGlyphId) const {
|
||||
DeviceColor ctxColor;
|
||||
sRGBColor currentColor = aContext->GetDeviceColor(ctxColor)
|
||||
? sRGBColor::FromABGR(ctxColor.ToABGR())
|
||||
: sRGBColor::OpaqueBlack();
|
||||
auto currentColor = [=]() {
|
||||
DeviceColor ctxColor;
|
||||
return aContext->GetDeviceColor(ctxColor)
|
||||
? sRGBColor::FromABGR(ctxColor.ToABGR())
|
||||
: sRGBColor::OpaqueBlack();
|
||||
};
|
||||
|
||||
if (const auto* layers =
|
||||
COLRFonts::GetGlyphLayers(GetFontEntry()->GetCOLR(), aGlyphId)) {
|
||||
return COLRFonts::PaintGlyphLayers(GetFontEntry()->GetCOLR(),
|
||||
GetFontEntry()->GetCPAL(), layers,
|
||||
aDrawTarget, aTextDrawer, aScaledFont,
|
||||
aDrawOptions, currentColor, aPoint);
|
||||
auto face(GetFontEntry()->GetHBFace());
|
||||
bool ok = COLRFonts::PaintGlyphLayers(
|
||||
GetFontEntry()->GetCOLR(), face, layers, aDrawTarget, aTextDrawer,
|
||||
aScaledFont, aDrawOptions, currentColor(), aPoint);
|
||||
return ok;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
Загрузка…
Ссылка в новой задаче