mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 889401 - Part 2. Render color glyph using COLR/CPAL. r=jfkthame
This commit is contained in:
parent
aa083bc07a
commit
c34e56df8b
@ -123,9 +123,12 @@ gfxFontEntry::gfxFontEntry() :
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mCheckedForColorGlyph(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mCOLR(nullptr),
|
||||
mCPAL(nullptr),
|
||||
mUnitsPerEm(0),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
@ -153,9 +156,12 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mCheckedForColorGlyph(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mCOLR(nullptr),
|
||||
mCPAL(nullptr),
|
||||
mUnitsPerEm(0),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
@ -167,6 +173,14 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
|
||||
|
||||
gfxFontEntry::~gfxFontEntry()
|
||||
{
|
||||
if (mCOLR) {
|
||||
hb_blob_destroy(mCOLR);
|
||||
}
|
||||
|
||||
if (mCPAL) {
|
||||
hb_blob_destroy(mCPAL);
|
||||
}
|
||||
|
||||
// For downloaded fonts, we need to tell the user font cache that this
|
||||
// entry is being deleted.
|
||||
if (!mIsProxy && IsUserFont() && !IsLocalUserFont()) {
|
||||
@ -482,6 +496,39 @@ gfxFontEntry::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
|
||||
return mMathTable->GetMathVariantsParts(aGlyphID, aVertical, aGlyphs);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFontEntry::TryGetColorGlyphs()
|
||||
{
|
||||
if (mCheckedForColorGlyph) {
|
||||
return (mCOLR && mCPAL);
|
||||
}
|
||||
|
||||
mCheckedForColorGlyph = true;
|
||||
|
||||
mCOLR = GetFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R'));
|
||||
if (!mCOLR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mCPAL = GetFontTable(TRUETYPE_TAG('C', 'P', 'A', 'L'));
|
||||
if (!mCPAL) {
|
||||
hb_blob_destroy(mCOLR);
|
||||
mCOLR = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// validation COLR and CPAL table
|
||||
if (gfxFontUtils::ValidateColorGlyphs(mCOLR, mCPAL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_blob_destroy(mCOLR);
|
||||
hb_blob_destroy(mCPAL);
|
||||
mCOLR = nullptr;
|
||||
mCPAL = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* FontTableBlobData
|
||||
*
|
||||
@ -830,6 +877,18 @@ gfxFontEntry::CheckForGraphiteTables()
|
||||
mHasGraphiteTables = HasFontTable(TRUETYPE_TAG('S','i','l','f'));
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFontEntry::GetColorLayersInfo(uint32_t aGlyphId,
|
||||
nsTArray<uint16_t>& aLayerGlyphs,
|
||||
nsTArray<mozilla::gfx::Color>& aLayerColors)
|
||||
{
|
||||
return gfxFontUtils::GetColorGlyphLayers(mCOLR,
|
||||
mCPAL,
|
||||
aGlyphId,
|
||||
aLayerGlyphs,
|
||||
aLayerColors);
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
gfxFontEntry::FontTableHashEntry::SizeOfEntryExcludingThis
|
||||
(FontTableHashEntry *aEntry,
|
||||
@ -2867,6 +2926,7 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
gfxMatrix globalMatrix = aContext->CurrentMatrix();
|
||||
|
||||
bool haveSVGGlyphs = GetFontEntry()->TryGetSVGData(this);
|
||||
bool haveColorGlyphs = GetFontEntry()->TryGetColorGlyphs();
|
||||
nsAutoPtr<gfxTextContextPaint> contextPaint;
|
||||
if (haveSVGGlyphs && !aContextPaint) {
|
||||
// If no pattern is specified for fill, use the current pattern
|
||||
@ -2939,6 +2999,14 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
}
|
||||
}
|
||||
|
||||
if (haveColorGlyphs) {
|
||||
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
if (RenderColorGlyph(aContext, point, glyphData->GetSimpleGlyph())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Perhaps we should put a scale in the cairo context instead of
|
||||
// doing this scaling here...
|
||||
// Multiplying by the reciprocal may introduce tiny error here,
|
||||
@ -3001,13 +3069,14 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
glyphX -= advance;
|
||||
}
|
||||
|
||||
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
|
||||
if (haveSVGGlyphs) {
|
||||
if (!paintSVGGlyphs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gfxPoint point(ToDeviceUnits(glyphX, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
|
||||
DrawMode mode = ForcePaintingDrawMode(aDrawMode);
|
||||
if (RenderSVGGlyph(aContext, point, mode,
|
||||
details->mGlyphID,
|
||||
@ -3017,6 +3086,17 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
}
|
||||
}
|
||||
|
||||
if (haveColorGlyphs) {
|
||||
gfxPoint point(ToDeviceUnits(glyphX,
|
||||
devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y + details->mYOffset,
|
||||
devUnitsPerAppUnit));
|
||||
if (RenderColorGlyph(aContext, point,
|
||||
details->mGlyphID)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
glyph = glyphs.AppendGlyph();
|
||||
glyph->index = details->mGlyphID;
|
||||
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
@ -3157,6 +3237,18 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
}
|
||||
}
|
||||
|
||||
if (haveColorGlyphs) {
|
||||
mozilla::gfx::Point point(ToDeviceUnits(glyphX,
|
||||
devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y,
|
||||
devUnitsPerAppUnit));
|
||||
if (RenderColorGlyph(aContext, scaledFont, renderingOptions,
|
||||
drawOptions, matInv * point,
|
||||
glyphData->GetSimpleGlyph())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Perhaps we should put a scale in the cairo context instead of
|
||||
// doing this scaling here...
|
||||
// Multiplying by the reciprocal may introduce tiny error here,
|
||||
@ -3243,6 +3335,19 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
}
|
||||
}
|
||||
|
||||
if (haveColorGlyphs) {
|
||||
mozilla::gfx::Point point(ToDeviceUnits(glyphX,
|
||||
devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y + details->mYOffset,
|
||||
devUnitsPerAppUnit));
|
||||
if (RenderColorGlyph(aContext, scaledFont,
|
||||
renderingOptions,
|
||||
drawOptions, matInv * point,
|
||||
details->mGlyphID)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
glyph = glyphs.AppendGlyph();
|
||||
glyph->mIndex = details->mGlyphID;
|
||||
glyph->mPosition.x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
|
||||
@ -3343,6 +3448,73 @@ gfxFont::RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMod
|
||||
return rendered;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFont::RenderColorGlyph(gfxContext* aContext, gfxPoint& point,
|
||||
uint32_t aGlyphId)
|
||||
{
|
||||
nsAutoTArray<uint16_t, 8> layerGlyphs;
|
||||
nsAutoTArray<mozilla::gfx::Color, 8> layerColors;
|
||||
|
||||
if (!GetFontEntry()->GetColorLayersInfo(aGlyphId, layerGlyphs, layerColors)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cairo_t* cr = aContext->GetCairo();
|
||||
cairo_save(cr);
|
||||
for (uint32_t layerIndex = 0; layerIndex < layerGlyphs.Length();
|
||||
layerIndex++) {
|
||||
|
||||
cairo_glyph_t glyph;
|
||||
glyph.index = layerGlyphs[layerIndex];
|
||||
glyph.x = point.x;
|
||||
glyph.y = point.y;
|
||||
|
||||
mozilla::gfx::Color &color = layerColors[layerIndex];
|
||||
cairo_pattern_t* pattern =
|
||||
cairo_pattern_create_rgba(color.r, color.g, color.b, color.a);
|
||||
|
||||
cairo_set_source(cr, pattern);
|
||||
cairo_show_glyphs(cr, &glyph, 1);
|
||||
cairo_pattern_destroy(pattern);
|
||||
}
|
||||
cairo_restore(cr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFont::RenderColorGlyph(gfxContext* aContext,
|
||||
mozilla::gfx::ScaledFont* scaledFont,
|
||||
GlyphRenderingOptions* aRenderingOptions,
|
||||
mozilla::gfx::DrawOptions aDrawOptions,
|
||||
const mozilla::gfx::Point& aPoint,
|
||||
uint32_t aGlyphId)
|
||||
{
|
||||
nsAutoTArray<uint16_t, 8> layerGlyphs;
|
||||
nsAutoTArray<mozilla::gfx::Color, 8> layerColors;
|
||||
|
||||
if (!GetFontEntry()->GetColorLayersInfo(aGlyphId, layerGlyphs, layerColors)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
|
||||
for (uint32_t layerIndex = 0; layerIndex < layerGlyphs.Length();
|
||||
layerIndex++) {
|
||||
Glyph glyph;
|
||||
glyph.mIndex = layerGlyphs[layerIndex];
|
||||
glyph.mPosition = aPoint;
|
||||
|
||||
mozilla::gfx::GlyphBuffer buffer;
|
||||
buffer.mGlyphs = &glyph;
|
||||
buffer.mNumGlyphs = 1;
|
||||
|
||||
dt->FillGlyphs(scaledFont, buffer,
|
||||
ColorPattern(layerColors[layerIndex]),
|
||||
aDrawOptions, aRenderingOptions);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
UnionRange(gfxFloat aX, gfxFloat* aDestMin, gfxFloat* aDestMax)
|
||||
{
|
||||
|
@ -389,6 +389,11 @@ public:
|
||||
bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
|
||||
uint32_t aGlyphs[4]);
|
||||
|
||||
bool TryGetColorGlyphs();
|
||||
bool GetColorLayersInfo(uint32_t aGlyphId,
|
||||
nsTArray<uint16_t>& layerGlyphs,
|
||||
nsTArray<mozilla::gfx::Color>& layerColors);
|
||||
|
||||
virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
|
||||
return true;
|
||||
}
|
||||
@ -531,6 +536,7 @@ public:
|
||||
bool mCheckedForGraphiteTables : 1;
|
||||
bool mHasCmapTable : 1;
|
||||
bool mGrFaceInitialized : 1;
|
||||
bool mCheckedForColorGlyph : 1;
|
||||
|
||||
// bitvector of substitution space features per script, one each
|
||||
// for default and non-default features
|
||||
@ -551,6 +557,10 @@ public:
|
||||
nsTArray<gfxFontFeature> mFeatureSettings;
|
||||
uint32_t mLanguageOverride;
|
||||
|
||||
// Color Layer font support
|
||||
hb_blob_t* mCOLR;
|
||||
hb_blob_t* mCPAL;
|
||||
|
||||
protected:
|
||||
friend class gfxPlatformFontList;
|
||||
friend class gfxMacPlatformFontList;
|
||||
@ -2135,6 +2145,14 @@ protected:
|
||||
gfxTextRunDrawCallbacks *aCallbacks,
|
||||
bool& aEmittedGlyphs);
|
||||
|
||||
bool RenderColorGlyph(gfxContext* aContext, gfxPoint& point, uint32_t aGlyphId);
|
||||
bool RenderColorGlyph(gfxContext* aContext,
|
||||
mozilla::gfx::ScaledFont* scaledFont,
|
||||
mozilla::gfx::GlyphRenderingOptions* renderingOptions,
|
||||
mozilla::gfx::DrawOptions drawOptions,
|
||||
const mozilla::gfx::Point& aPoint,
|
||||
uint32_t aGlyphId);
|
||||
|
||||
// Bug 674909. When synthetic bolding text by drawing twice, need to
|
||||
// render using a pixel offset in device pixels, otherwise text
|
||||
// doesn't appear bolded, it appears as if a bad text shadow exists
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "gfxFontUtils.h"
|
||||
#include "gfxColor.h"
|
||||
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
@ -1439,6 +1440,215 @@ gfxFontUtils::ReadNames(const char *aNameData, uint32_t aDataLen,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct COLRBaseGlyphRecord {
|
||||
AutoSwap_PRUint16 glyphId;
|
||||
AutoSwap_PRUint16 firstLayerIndex;
|
||||
AutoSwap_PRUint16 numLayers;
|
||||
};
|
||||
|
||||
struct COLRLayerRecord {
|
||||
AutoSwap_PRUint16 glyphId;
|
||||
AutoSwap_PRUint16 paletteEntryIndex;
|
||||
};
|
||||
|
||||
struct CPALColorRecord {
|
||||
uint8_t blue;
|
||||
uint8_t green;
|
||||
uint8_t red;
|
||||
uint8_t alpha;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
bool
|
||||
gfxFontUtils::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));
|
||||
unsigned int cpalLength;
|
||||
const CPALHeaderVersion0* cpal =
|
||||
reinterpret_cast<const CPALHeaderVersion0*>(hb_blob_get_data(aCPAL, &cpalLength));
|
||||
|
||||
if (!colr || !cpal || !colrLength || !cpalLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint16_t(colr->version) != 0 || uint16_t(cpal->version) != 0) {
|
||||
// We only support version 0 headers.
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t offsetBaseGlyphRecord = colr->offsetBaseGlyphRecord;
|
||||
const uint16_t numBaseGlyphRecord = colr->numBaseGlyphRecord;
|
||||
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;
|
||||
}
|
||||
|
||||
if (offsetLayerRecord >= colrLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offsetFirstColorRecord >= cpalLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!numPaletteEntries) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sizeof(COLRBaseGlyphRecord) * numBaseGlyphRecord >
|
||||
colrLength - offsetBaseGlyphRecord) {
|
||||
// COLR base glyph record will be overflow
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sizeof(COLRLayerRecord) * numLayerRecords >
|
||||
colrLength - offsetLayerRecord) {
|
||||
// COLR layer record will be overflow
|
||||
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*>(
|
||||
reinterpret_cast<const uint8_t*>(colr) + offsetBaseGlyphRecord);
|
||||
|
||||
for (uint16_t i = 0; i < numBaseGlyphRecord; i++, baseGlyph++) {
|
||||
const uint32_t firstLayerIndex = baseGlyph->firstLayerIndex;
|
||||
const uint16_t numLayers = baseGlyph->numLayers;
|
||||
const uint16_t glyphId = baseGlyph->glyphId;
|
||||
|
||||
if (lastGlyphId && lastGlyphId >= glyphId) {
|
||||
// glyphId must be sorted
|
||||
return false;
|
||||
}
|
||||
lastGlyphId = glyphId;
|
||||
|
||||
if (!numLayers) {
|
||||
// no layer
|
||||
return false;
|
||||
}
|
||||
if (firstLayerIndex + numLayers > numLayerRecords) {
|
||||
// layer length of target glyph is overflow
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const COLRLayerRecord* layer =
|
||||
reinterpret_cast<const COLRLayerRecord*>(
|
||||
reinterpret_cast<const uint8_t*>(colr) + offsetLayerRecord);
|
||||
|
||||
for (uint16_t i = 0; i < numLayerRecords; i++, layer++) {
|
||||
if (uint16_t(layer->paletteEntryIndex) >= numPaletteEntries) {
|
||||
// CPAL palette entry record is overflow
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
CompareBaseGlyph(const void* key, const void* data)
|
||||
{
|
||||
uint32_t glyphId = (uint32_t)(uintptr_t)key;
|
||||
const COLRBaseGlyphRecord* baseGlyph =
|
||||
reinterpret_cast<const COLRBaseGlyphRecord*>(data);
|
||||
uint32_t baseGlyphId = uint16_t(baseGlyph->glyphId);
|
||||
|
||||
if (baseGlyphId == glyphId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return baseGlyphId > glyphId ? -1 : 1;
|
||||
}
|
||||
|
||||
static
|
||||
COLRBaseGlyphRecord*
|
||||
LookForBaseGlyphRecord(const COLRHeader* aCOLR, uint32_t aGlyphId)
|
||||
{
|
||||
const uint8_t* baseGlyphRecords =
|
||||
reinterpret_cast<const uint8_t*>(aCOLR) +
|
||||
uint32_t(aCOLR->offsetBaseGlyphRecord);
|
||||
// BaseGlyphRecord is sorted by glyphId
|
||||
return reinterpret_cast<COLRBaseGlyphRecord*>(
|
||||
bsearch((void*)(uintptr_t)aGlyphId,
|
||||
baseGlyphRecords,
|
||||
uint16_t(aCOLR->numBaseGlyphRecord),
|
||||
sizeof(COLRBaseGlyphRecord),
|
||||
CompareBaseGlyph));
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFontUtils::GetColorGlyphLayers(hb_blob_t* aCOLR,
|
||||
hb_blob_t* aCPAL,
|
||||
uint32_t aGlyphId,
|
||||
nsTArray<uint16_t>& aGlyphs,
|
||||
nsTArray<mozilla::gfx::Color>& aColors)
|
||||
{
|
||||
unsigned int blobLength;
|
||||
const COLRHeader* colr =
|
||||
reinterpret_cast<const COLRHeader*>(hb_blob_get_data(aCOLR,
|
||||
&blobLength));
|
||||
MOZ_ASSERT(colr, "Cannot get COLR raw data");
|
||||
MOZ_ASSERT(blobLength, "Found COLR data, but length is 0");
|
||||
|
||||
COLRBaseGlyphRecord* baseGlyph = LookForBaseGlyphRecord(colr, aGlyphId);
|
||||
if (!baseGlyph) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const CPALHeaderVersion0* cpal =
|
||||
reinterpret_cast<const CPALHeaderVersion0*>(
|
||||
hb_blob_get_data(aCPAL, &blobLength));
|
||||
MOZ_ASSERT(cpal, "Cannot get CPAL raw data");
|
||||
MOZ_ASSERT(blobLength, "Found CPAL data, but length is 0");
|
||||
|
||||
const COLRLayerRecord* layer =
|
||||
reinterpret_cast<const COLRLayerRecord*>(
|
||||
reinterpret_cast<const uint8_t*>(colr) +
|
||||
uint32_t(colr->offsetLayerRecord) +
|
||||
sizeof(COLRLayerRecord) * uint16_t(baseGlyph->firstLayerIndex));
|
||||
const uint16_t numLayers = baseGlyph->numLayers;
|
||||
const uint32_t offsetFirstColorRecord = cpal->offsetFirstColorRecord;
|
||||
|
||||
for (uint16_t layerIndex = 0; layerIndex < numLayers; layerIndex++) {
|
||||
aGlyphs.AppendElement(uint16_t(layer->glyphId));
|
||||
const CPALColorRecord* color =
|
||||
reinterpret_cast<const CPALColorRecord*>(
|
||||
reinterpret_cast<const uint8_t*>(cpal) +
|
||||
offsetFirstColorRecord +
|
||||
sizeof(CPALColorRecord) * uint16_t(layer->paletteEntryIndex));
|
||||
aColors.AppendElement(mozilla::gfx::Color(color->red / 255.0,
|
||||
color->green / 255.0,
|
||||
color->blue / 255.0,
|
||||
color->alpha / 255.0));
|
||||
layer++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
/* static */
|
||||
|
@ -605,6 +605,22 @@ struct KernTableSubtableHeaderVersion1 {
|
||||
AutoSwap_PRUint16 tupleIndex;
|
||||
};
|
||||
|
||||
struct COLRHeader {
|
||||
AutoSwap_PRUint16 version;
|
||||
AutoSwap_PRUint16 numBaseGlyphRecord;
|
||||
AutoSwap_PRUint32 offsetBaseGlyphRecord;
|
||||
AutoSwap_PRUint32 offsetLayerRecord;
|
||||
AutoSwap_PRUint16 numLayerRecords;
|
||||
};
|
||||
|
||||
struct CPALHeaderVersion0 {
|
||||
AutoSwap_PRUint16 version;
|
||||
AutoSwap_PRUint16 numPaletteEntries;
|
||||
AutoSwap_PRUint16 numPalettes;
|
||||
AutoSwap_PRUint16 numColorRecords;
|
||||
AutoSwap_PRUint32 offsetFirstColorRecord;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
// Return just the highest bit of the given value, i.e., the highest
|
||||
@ -926,6 +942,14 @@ public:
|
||||
// generate a unique font name
|
||||
static nsresult MakeUniqueUserFontName(nsAString& aName);
|
||||
|
||||
// for color layer from glyph using COLR and CPAL tables
|
||||
static bool ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL);
|
||||
static bool GetColorGlyphLayers(hb_blob_t* aCOLR,
|
||||
hb_blob_t* aCPAL,
|
||||
uint32_t aGlyphId,
|
||||
nsTArray<uint16_t> &aGlyphs,
|
||||
nsTArray<mozilla::gfx::Color> &aColors);
|
||||
|
||||
protected:
|
||||
static nsresult
|
||||
ReadNames(const char *aNameData, uint32_t aDataLen, uint32_t aNameID,
|
||||
|
@ -333,13 +333,15 @@ private:
|
||||
static ots::TableAction
|
||||
OTSTableAction(uint32_t aTag, void *aUserData)
|
||||
{
|
||||
// preserve Graphite and SVG tables
|
||||
// preserve Graphite, color glyph and SVG tables
|
||||
if (aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
|
||||
aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
|
||||
aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
|
||||
aTag == TRUETYPE_TAG('G', 'l', 'a', 't') ||
|
||||
aTag == TRUETYPE_TAG('F', 'e', 'a', 't') ||
|
||||
aTag == TRUETYPE_TAG('S', 'V', 'G', ' ')) {
|
||||
aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') ||
|
||||
aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') ||
|
||||
aTag == TRUETYPE_TAG('C', 'P', 'A', 'L')) {
|
||||
return ots::TABLE_ACTION_PASSTHRU;
|
||||
}
|
||||
return ots::TABLE_ACTION_DEFAULT;
|
||||
|
Loading…
Reference in New Issue
Block a user