mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-05 05:30:29 +00:00
Bug 902762 pt 1 - Pass a 'vertical' flag to font shapers, and support vertical shaping through harfbuzz. r=jdaggett
This commit is contained in:
parent
80d061a15b
commit
b2c88c5dfe
@ -52,6 +52,7 @@ gfxCoreTextShaper::ShapeText(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
// Create a CFAttributedString with text and style info, so we can use CoreText to lay it out.
|
||||
|
@ -23,6 +23,7 @@ public:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
// clean up static objects that may have been cached
|
||||
|
@ -219,9 +219,10 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
|
||||
TRUETYPE_TAG('h','h','e','a'));
|
||||
if (hheaTable) {
|
||||
uint32_t len;
|
||||
const HheaTable* hhea =
|
||||
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
|
||||
if (len >= sizeof(HheaTable)) {
|
||||
const MetricsHeader* hhea =
|
||||
reinterpret_cast<const MetricsHeader*>
|
||||
(hb_blob_get_data(hheaTable, &len));
|
||||
if (len >= sizeof(MetricsHeader)) {
|
||||
mMetrics->maxAdvance =
|
||||
uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
|
||||
}
|
||||
|
@ -48,10 +48,11 @@ gfxFT2Font::ShapeText(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
|
||||
aShapedText)) {
|
||||
aVertical, aShapedText)) {
|
||||
// harfbuzz must have failed(?!), just render raw glyphs
|
||||
AddRange(aText, aOffset, aLength, aShapedText);
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
@ -77,6 +77,7 @@ protected:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
void FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd);
|
||||
|
@ -2214,6 +2214,7 @@ gfxFont::GetShapedWord(gfxContext *aContext,
|
||||
uint32_t aLength,
|
||||
uint32_t aHash,
|
||||
int32_t aRunScript,
|
||||
bool aVertical,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags,
|
||||
gfxTextPerfMetrics *aTextPerf GFX_MAYBE_UNUSED)
|
||||
@ -2273,7 +2274,7 @@ gfxFont::GetShapedWord(gfxContext *aContext,
|
||||
}
|
||||
|
||||
DebugOnly<bool> ok =
|
||||
ShapeText(aContext, aText, 0, aLength, aRunScript, sw);
|
||||
ShapeText(aContext, aText, 0, aLength, aRunScript, aVertical, sw);
|
||||
|
||||
NS_WARN_IF_FALSE(ok, "failed to shape word - expect garbled text");
|
||||
|
||||
@ -2323,6 +2324,7 @@ gfxFont::ShapeText(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
nsDependentCSubstring ascii((const char*)aText, aLength);
|
||||
@ -2332,7 +2334,7 @@ gfxFont::ShapeText(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
return ShapeText(aContext, utf16.BeginReading(), aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
aScript, aVertical, aShapedText);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2341,17 +2343,20 @@ gfxFont::ShapeText(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if (FontCanSupportGraphite()) {
|
||||
// XXX Currently, we do all vertical shaping through harfbuzz.
|
||||
// Vertical graphite support may be wanted as a future enhancement.
|
||||
if (FontCanSupportGraphite() && !aVertical) {
|
||||
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
if (!mGraphiteShaper) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
aScript, aVertical, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2360,7 +2365,7 @@ gfxFont::ShapeText(gfxContext *aContext,
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
aScript, aVertical, aShapedText);
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
|
||||
@ -2397,6 +2402,7 @@ gfxFont::ShapeFragmentWithoutWordCache(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxTextRun *aTextRun)
|
||||
{
|
||||
aTextRun->SetupClusterBoundaries(aOffset, aText, aLength);
|
||||
@ -2432,7 +2438,8 @@ gfxFont::ShapeFragmentWithoutWordCache(gfxContext *aContext,
|
||||
}
|
||||
}
|
||||
|
||||
ok = ShapeText(aContext, aText, aOffset, fragLen, aScript, aTextRun);
|
||||
ok = ShapeText(aContext, aText, aOffset, fragLen, aScript, aVertical,
|
||||
aTextRun);
|
||||
|
||||
aText += fragLen;
|
||||
aOffset += fragLen;
|
||||
@ -2460,6 +2467,7 @@ gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxTextRun *aTextRun)
|
||||
{
|
||||
uint32_t fragStart = 0;
|
||||
@ -2478,7 +2486,7 @@ gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
|
||||
if (length > 0) {
|
||||
ok = ShapeFragmentWithoutWordCache(aContext, aText + fragStart,
|
||||
aOffset + fragStart, length,
|
||||
aScript, aTextRun);
|
||||
aScript, aVertical, aTextRun);
|
||||
}
|
||||
|
||||
if (i == aLength) {
|
||||
@ -2534,7 +2542,8 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
const T *aString, // text for this font run
|
||||
uint32_t aRunStart, // position in the textrun
|
||||
uint32_t aRunLength,
|
||||
int32_t aRunScript)
|
||||
int32_t aRunScript,
|
||||
bool aVertical)
|
||||
{
|
||||
if (aRunLength == 0) {
|
||||
return true;
|
||||
@ -2569,7 +2578,8 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
HasSpaces(aString, aRunLength)) {
|
||||
TEXT_PERF_INCR(tp, wordCacheSpaceRules);
|
||||
return ShapeTextWithoutWordCache(aContext, aString,
|
||||
aRunStart, aRunLength, aRunScript,
|
||||
aRunStart, aRunLength,
|
||||
aRunScript, aVertical,
|
||||
aTextRun);
|
||||
}
|
||||
}
|
||||
@ -2622,6 +2632,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
aRunStart + wordStart,
|
||||
length,
|
||||
aRunScript,
|
||||
aVertical,
|
||||
aTextRun);
|
||||
if (!ok) {
|
||||
return false;
|
||||
@ -2638,7 +2649,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
}
|
||||
gfxShapedWord *sw = GetShapedWord(aContext,
|
||||
aString + wordStart, length,
|
||||
hash, aRunScript,
|
||||
hash, aRunScript, aVertical,
|
||||
appUnitsPerDevUnit,
|
||||
wordFlags, tp);
|
||||
if (sw) {
|
||||
@ -2652,7 +2663,9 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
// word was terminated by a space: add that to the textrun
|
||||
uint16_t orientation = flags & gfxTextRunFactory::TEXT_ORIENT_MASK;
|
||||
if (orientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED) {
|
||||
orientation = gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
|
||||
orientation = aVertical ?
|
||||
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT :
|
||||
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
|
||||
}
|
||||
if (!aTextRun->SetSpaceGlyphIfSimple(this, aContext,
|
||||
aRunStart + i, ch,
|
||||
@ -2662,7 +2675,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
gfxShapedWord *sw =
|
||||
GetShapedWord(aContext,
|
||||
&space, 1,
|
||||
gfxShapedWord::HashMix(0, ' '), aRunScript,
|
||||
gfxShapedWord::HashMix(0, ' '), aRunScript, aVertical,
|
||||
appUnitsPerDevUnit,
|
||||
flags | gfxTextRunFactory::TEXT_IS_8BIT, tp);
|
||||
if (sw) {
|
||||
@ -2711,15 +2724,17 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
const uint8_t *aString,
|
||||
uint32_t aRunStart,
|
||||
uint32_t aRunLength,
|
||||
int32_t aRunScript);
|
||||
int32_t aRunScript,
|
||||
bool aVertical);
|
||||
template bool
|
||||
gfxFont::SplitAndInitTextRun(gfxContext *aContext,
|
||||
gfxTextRun *aTextRun,
|
||||
const char16_t *aString,
|
||||
uint32_t aRunStart,
|
||||
uint32_t aRunLength,
|
||||
int32_t aRunScript);
|
||||
|
||||
int32_t aRunScript,
|
||||
bool aVertical);
|
||||
|
||||
template<>
|
||||
bool
|
||||
gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
||||
@ -2745,6 +2760,8 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
||||
|
||||
RunCaseAction runAction = kNoChange;
|
||||
uint32_t runStart = 0;
|
||||
bool vertical =
|
||||
aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
|
||||
|
||||
for (uint32_t i = 0; i <= aLength; ++i) {
|
||||
uint32_t extraCodeUnits = 0; // Will be set to 1 if we need to consume
|
||||
@ -2803,7 +2820,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
||||
if (!f->SplitAndInitTextRun(aContext, aTextRun,
|
||||
aText + runStart,
|
||||
aOffset + runStart, runLength,
|
||||
aScript)) {
|
||||
aScript, vertical)) {
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
@ -2844,7 +2861,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
||||
if (!f->SplitAndInitTextRun(aContext, tempRun,
|
||||
convertedString.BeginReading(),
|
||||
0, convertedString.Length(),
|
||||
aScript)) {
|
||||
aScript, vertical)) {
|
||||
ok = false;
|
||||
} else {
|
||||
nsAutoPtr<gfxTextRun> mergedRun;
|
||||
@ -2863,7 +2880,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
||||
if (!f->SplitAndInitTextRun(aContext, aTextRun,
|
||||
convertedString.BeginReading(),
|
||||
aOffset + runStart, runLength,
|
||||
aScript)) {
|
||||
aScript, vertical)) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
@ -3024,9 +3041,10 @@ gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
|
||||
if (!hheaTable) {
|
||||
return false; // no 'hhea' table -> not an sfnt
|
||||
}
|
||||
const HheaTable* hhea =
|
||||
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
|
||||
if (len < sizeof(HheaTable)) {
|
||||
const MetricsHeader* hhea =
|
||||
reinterpret_cast<const MetricsHeader*>
|
||||
(hb_blob_get_data(hheaTable, &len));
|
||||
if (len < sizeof(MetricsHeader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3272,10 +3290,10 @@ gfxFont::CreateVerticalMetrics()
|
||||
if (!metrics->aveCharWidth) {
|
||||
gfxFontEntry::AutoTable hheaTable(mFontEntry, kHheaTableTag);
|
||||
if (hheaTable) {
|
||||
const HheaTable* hhea =
|
||||
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable,
|
||||
&len));
|
||||
if (len >= sizeof(HheaTable)) {
|
||||
const MetricsHeader* hhea =
|
||||
reinterpret_cast<const MetricsHeader*>
|
||||
(hb_blob_get_data(hheaTable, &len));
|
||||
if (len >= sizeof(MetricsHeader)) {
|
||||
SET_SIGNED(aveCharWidth, int16_t(hhea->ascender) -
|
||||
int16_t(hhea->descender));
|
||||
metrics->maxAscent = metrics->aveCharWidth / 2;
|
||||
@ -3288,10 +3306,10 @@ gfxFont::CreateVerticalMetrics()
|
||||
// Read real vertical metrics if available.
|
||||
gfxFontEntry::AutoTable vheaTable(mFontEntry, kVheaTableTag);
|
||||
if (vheaTable) {
|
||||
const HheaTable* vhea =
|
||||
reinterpret_cast<const HheaTable*>(hb_blob_get_data(vheaTable,
|
||||
&len));
|
||||
if (len >= sizeof(HheaTable)) {
|
||||
const MetricsHeader* vhea =
|
||||
reinterpret_cast<const MetricsHeader*>
|
||||
(hb_blob_get_data(vheaTable, &len));
|
||||
if (len >= sizeof(MetricsHeader)) {
|
||||
SET_UNSIGNED(maxAdvance, vhea->advanceWidthMax);
|
||||
SET_SIGNED(maxAscent, vhea->ascender);
|
||||
SET_SIGNED(maxDescent, -int16_t(vhea->descender));
|
||||
|
@ -610,6 +610,7 @@ public:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText) = 0;
|
||||
|
||||
gfxFont *GetFont() const { return mFont; }
|
||||
@ -1630,7 +1631,8 @@ public:
|
||||
const T *aString,
|
||||
uint32_t aRunStart,
|
||||
uint32_t aRunLength,
|
||||
int32_t aRunScript);
|
||||
int32_t aRunScript,
|
||||
bool aVertical);
|
||||
|
||||
// Get a ShapedWord representing the given text (either 8- or 16-bit)
|
||||
// for use in setting up a gfxTextRun.
|
||||
@ -1640,6 +1642,7 @@ public:
|
||||
uint32_t aLength,
|
||||
uint32_t aHash,
|
||||
int32_t aRunScript,
|
||||
bool aVertical,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags,
|
||||
gfxTextPerfMetrics *aTextPerf);
|
||||
@ -1816,6 +1819,7 @@ protected:
|
||||
uint32_t aOffset, // dest offset in gfxShapedText
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText); // where to store the result
|
||||
|
||||
// Call the appropriate shaper to generate glyphs for aText and store
|
||||
@ -1825,6 +1829,7 @@ protected:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
// Helper to adjust for synthetic bold and set character-type flags
|
||||
@ -1849,6 +1854,7 @@ protected:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxTextRun *aTextRun);
|
||||
|
||||
// Shape a fragment of text (a run that is known to contain only
|
||||
@ -1862,6 +1868,7 @@ protected:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxTextRun *aTextRun);
|
||||
|
||||
void CheckForFeaturesInvolvingSpace();
|
||||
|
@ -553,7 +553,10 @@ struct PostTable {
|
||||
AutoSwap_PRUint32 maxMemType1;
|
||||
};
|
||||
|
||||
struct HheaTable {
|
||||
// This structure is used for both 'hhea' and 'vhea' tables.
|
||||
// The field names here are those of the horizontal version; the
|
||||
// vertical table just exchanges vertical and horizontal coordinates.
|
||||
struct MetricsHeader {
|
||||
AutoSwap_PRUint32 version;
|
||||
AutoSwap_PRInt16 ascender;
|
||||
AutoSwap_PRInt16 descender;
|
||||
@ -570,7 +573,7 @@ struct HheaTable {
|
||||
AutoSwap_PRInt16 reserved3;
|
||||
AutoSwap_PRInt16 reserved4;
|
||||
AutoSwap_PRInt16 metricDataFormat;
|
||||
AutoSwap_PRUint16 numOfLongHorMetrics;
|
||||
AutoSwap_PRUint16 numOfLongMetrics;
|
||||
};
|
||||
|
||||
struct MaxpTableHeader {
|
||||
|
@ -83,6 +83,7 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
if (!mMetrics) {
|
||||
@ -102,7 +103,7 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
|
||||
}
|
||||
|
||||
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
|
||||
aShapedText);
|
||||
aVertical, aShapedText);
|
||||
}
|
||||
|
||||
const gfxFont::Metrics&
|
||||
|
@ -77,6 +77,7 @@ protected:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
void Initialize(); // creates metrics and Cairo fonts
|
||||
|
@ -89,6 +89,7 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
// some font back-ends require this in order to get proper hinted metrics
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
static void Shutdown();
|
||||
|
@ -39,14 +39,18 @@ gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont)
|
||||
mHBFont(nullptr),
|
||||
mKernTable(nullptr),
|
||||
mHmtxTable(nullptr),
|
||||
mNumLongMetrics(0),
|
||||
mVmtxTable(nullptr),
|
||||
mVORGTable(nullptr),
|
||||
mCmapTable(nullptr),
|
||||
mCmapFormat(-1),
|
||||
mSubtableOffset(0),
|
||||
mUVSTableOffset(0),
|
||||
mNumLongHMetrics(0),
|
||||
mNumLongVMetrics(0),
|
||||
mUseFontGetGlyph(aFont->ProvidesGetGlyph()),
|
||||
mUseFontGlyphWidths(false),
|
||||
mInitialized(false)
|
||||
mInitialized(false),
|
||||
mVerticalInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -166,30 +170,15 @@ HBGetGlyph(hb_font_t *font, void *font_data,
|
||||
return *glyph != 0;
|
||||
}
|
||||
|
||||
struct HMetricsHeader {
|
||||
AutoSwap_PRUint32 tableVersionNumber;
|
||||
AutoSwap_PRInt16 ascender;
|
||||
AutoSwap_PRInt16 descender;
|
||||
AutoSwap_PRInt16 lineGap;
|
||||
AutoSwap_PRUint16 advanceWidthMax;
|
||||
AutoSwap_PRInt16 minLeftSideBearing;
|
||||
AutoSwap_PRInt16 minRightSideBearing;
|
||||
AutoSwap_PRInt16 xMaxExtent;
|
||||
AutoSwap_PRInt16 caretSlopeRise;
|
||||
AutoSwap_PRInt16 caretSlopeRun;
|
||||
AutoSwap_PRInt16 caretOffset;
|
||||
AutoSwap_PRInt16 reserved[4];
|
||||
AutoSwap_PRInt16 metricDataFormat;
|
||||
AutoSwap_PRUint16 numberOfHMetrics;
|
||||
// Glyph metrics structures, shared (with appropriate reinterpretation of
|
||||
// field names) by horizontal and vertical metrics tables.
|
||||
struct LongMetric {
|
||||
AutoSwap_PRUint16 advanceWidth; // or advanceHeight, when vertical
|
||||
AutoSwap_PRInt16 lsb; // or tsb, when vertical
|
||||
};
|
||||
|
||||
struct HLongMetric {
|
||||
AutoSwap_PRUint16 advanceWidth;
|
||||
AutoSwap_PRInt16 lsb;
|
||||
};
|
||||
|
||||
struct HMetrics {
|
||||
HLongMetric metrics[1]; // actually numberOfHMetrics
|
||||
struct GlyphMetrics {
|
||||
LongMetric metrics[1]; // actually numberOfLongMetrics
|
||||
// the variable-length metrics[] array is immediately followed by:
|
||||
// AutoSwap_PRUint16 leftSideBearing[];
|
||||
};
|
||||
@ -198,23 +187,51 @@ hb_position_t
|
||||
gfxHarfBuzzShaper::GetGlyphHAdvance(gfxContext *aContext,
|
||||
hb_codepoint_t glyph) const
|
||||
{
|
||||
// font did not implement GetHintedGlyphWidth, so get an unhinted value
|
||||
// font did not implement GetGlyphWidth, so get an unhinted value
|
||||
// directly from the font tables
|
||||
|
||||
NS_ASSERTION((mNumLongMetrics > 0) && mHmtxTable != nullptr,
|
||||
NS_ASSERTION((mNumLongHMetrics > 0) && mHmtxTable != nullptr,
|
||||
"font is lacking metrics, we shouldn't be here");
|
||||
|
||||
if (glyph >= uint32_t(mNumLongMetrics)) {
|
||||
glyph = mNumLongMetrics - 1;
|
||||
if (glyph >= uint32_t(mNumLongHMetrics)) {
|
||||
glyph = mNumLongHMetrics - 1;
|
||||
}
|
||||
|
||||
// glyph must be valid now, because we checked during initialization
|
||||
// that mNumLongMetrics is > 0, and that the hmtx table is large enough
|
||||
// to contain mNumLongMetrics records
|
||||
const HMetrics* hmtx =
|
||||
reinterpret_cast<const HMetrics*>(hb_blob_get_data(mHmtxTable, nullptr));
|
||||
// that mNumLongHMetrics is > 0, and that the metrics table is large enough
|
||||
// to contain mNumLongHMetrics records
|
||||
const GlyphMetrics* metrics =
|
||||
reinterpret_cast<const GlyphMetrics*>(hb_blob_get_data(mHmtxTable,
|
||||
nullptr));
|
||||
return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
|
||||
uint16_t(hmtx->metrics[glyph].advanceWidth));
|
||||
uint16_t(metrics->metrics[glyph].advanceWidth));
|
||||
}
|
||||
|
||||
hb_position_t
|
||||
gfxHarfBuzzShaper::GetGlyphVAdvance(gfxContext *aContext,
|
||||
hb_codepoint_t glyph) const
|
||||
{
|
||||
if (!mVmtxTable) {
|
||||
// Must be a "vertical" font that doesn't actually have vertical metrics;
|
||||
// use a fixed advance.
|
||||
return FloatToFixed(mFont->GetMetrics(gfxFont::eVertical).aveCharWidth);
|
||||
}
|
||||
|
||||
NS_ASSERTION(mNumLongVMetrics > 0,
|
||||
"font is lacking metrics, we shouldn't be here");
|
||||
|
||||
if (glyph >= uint32_t(mNumLongVMetrics)) {
|
||||
glyph = mNumLongVMetrics - 1;
|
||||
}
|
||||
|
||||
// glyph must be valid now, because we checked during initialization
|
||||
// that mNumLongVMetrics is > 0, and that the metrics table is large enough
|
||||
// to contain mNumLongVMetrics records
|
||||
const GlyphMetrics* metrics =
|
||||
reinterpret_cast<const GlyphMetrics*>(hb_blob_get_data(mVmtxTable,
|
||||
nullptr));
|
||||
return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
|
||||
uint16_t(metrics->metrics[glyph].advanceWidth));
|
||||
}
|
||||
|
||||
/* static */
|
||||
@ -232,6 +249,111 @@ gfxHarfBuzzShaper::HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
hb_position_t
|
||||
gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph, void *user_data)
|
||||
{
|
||||
const gfxHarfBuzzShaper::FontCallbackData *fcd =
|
||||
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
|
||||
gfxFont *gfxfont = fcd->mShaper->GetFont();
|
||||
if (gfxfont->ProvidesGlyphWidths()) {
|
||||
return gfxfont->GetGlyphWidth(fcd->mContext, glyph);
|
||||
} else {
|
||||
return fcd->mShaper->GetGlyphVAdvance(fcd->mContext, glyph);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
hb_bool_t
|
||||
gfxHarfBuzzShaper::HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y,
|
||||
void *user_data)
|
||||
{
|
||||
// We work in horizontal coordinates, so no origin adjustment needed here.
|
||||
return true;
|
||||
}
|
||||
|
||||
struct VORG {
|
||||
AutoSwap_PRUint16 majorVersion;
|
||||
AutoSwap_PRUint16 minorVersion;
|
||||
AutoSwap_PRInt16 defaultVertOriginY;
|
||||
AutoSwap_PRUint16 numVertOriginYMetrics;
|
||||
};
|
||||
|
||||
struct VORGrec {
|
||||
AutoSwap_PRUint16 glyphIndex;
|
||||
AutoSwap_PRInt16 vertOriginY;
|
||||
};
|
||||
|
||||
/* static */
|
||||
hb_bool_t
|
||||
gfxHarfBuzzShaper::HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y,
|
||||
void *user_data)
|
||||
{
|
||||
const gfxHarfBuzzShaper::FontCallbackData *fcd =
|
||||
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
|
||||
fcd->mShaper->GetGlyphVOrigin(fcd->mContext, glyph, x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
gfxHarfBuzzShaper::GetGlyphVOrigin(gfxContext *aContext, hb_codepoint_t aGlyph,
|
||||
hb_position_t *aX, hb_position_t *aY) const
|
||||
{
|
||||
*aX = -0.5 * GetGlyphHAdvance(aContext, aGlyph);
|
||||
|
||||
if (mVORGTable) {
|
||||
// We checked in Initialize() that the VORG table is safely readable,
|
||||
// so no length/bounds-check needed here.
|
||||
const VORG* vorg =
|
||||
reinterpret_cast<const VORG*>(hb_blob_get_data(mVORGTable, nullptr));
|
||||
|
||||
const VORGrec *lo = reinterpret_cast<const VORGrec*>(vorg + 1);
|
||||
const VORGrec *hi = lo + uint16_t(vorg->numVertOriginYMetrics);
|
||||
const VORGrec *limit = hi;
|
||||
while (lo < hi) {
|
||||
const VORGrec *mid = lo + (hi - lo) / 2;
|
||||
if (uint16_t(mid->glyphIndex) < aGlyph) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
|
||||
if (lo < limit && uint16_t(lo->glyphIndex) == aGlyph) {
|
||||
*aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
|
||||
int16_t(lo->vertOriginY));
|
||||
} else {
|
||||
*aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
|
||||
int16_t(vorg->defaultVertOriginY));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX should we consider using OS/2 sTypo* metrics if available?
|
||||
|
||||
gfxFontEntry::AutoTable hheaTable(GetFont()->GetFontEntry(),
|
||||
TRUETYPE_TAG('h','h','e','a'));
|
||||
if (hheaTable) {
|
||||
uint32_t len;
|
||||
const MetricsHeader* hhea =
|
||||
reinterpret_cast<const MetricsHeader*>(hb_blob_get_data(hheaTable,
|
||||
&len));
|
||||
if (len >= sizeof(MetricsHeader)) {
|
||||
*aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
|
||||
int16_t(hhea->ascender));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NS_NOTREACHED("we shouldn't be here!");
|
||||
*aY = -FloatToFixed(GetFont()->GetAdjustedSize() / 2);
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
HBGetContourPoint(hb_font_t *font, void *font_data,
|
||||
unsigned int point_index, hb_codepoint_t glyph,
|
||||
@ -858,6 +980,15 @@ gfxHarfBuzzShaper::Initialize()
|
||||
hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs,
|
||||
HBGetGlyphHAdvance,
|
||||
nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs,
|
||||
HBGetGlyphVAdvance,
|
||||
nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_h_origin_func(sHBFontFuncs,
|
||||
HBGetGlyphHOrigin,
|
||||
nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs,
|
||||
HBGetGlyphVOrigin,
|
||||
nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs,
|
||||
HBGetContourPoint,
|
||||
nullptr, nullptr);
|
||||
@ -910,36 +1041,9 @@ gfxHarfBuzzShaper::Initialize()
|
||||
}
|
||||
|
||||
if (!mUseFontGlyphWidths) {
|
||||
// if font doesn't implement GetGlyphWidth, we will be reading
|
||||
// the hmtx table directly;
|
||||
// read mNumLongMetrics from hhea table without caching its blob,
|
||||
// and preload/cache the hmtx table
|
||||
gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a'));
|
||||
if (hheaTable) {
|
||||
uint32_t len;
|
||||
const HMetricsHeader* hhea =
|
||||
reinterpret_cast<const HMetricsHeader*>
|
||||
(hb_blob_get_data(hheaTable, &len));
|
||||
if (len >= sizeof(HMetricsHeader)) {
|
||||
mNumLongMetrics = hhea->numberOfHMetrics;
|
||||
if (mNumLongMetrics > 0 &&
|
||||
int16_t(hhea->metricDataFormat) == 0) {
|
||||
// no point reading hmtx if number of entries is zero!
|
||||
// in that case, we won't be able to use this font
|
||||
// (this method will return FALSE below if mHmtx is null)
|
||||
mHmtxTable =
|
||||
entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
|
||||
if (hb_blob_get_length(mHmtxTable) <
|
||||
mNumLongMetrics * sizeof(HLongMetric)) {
|
||||
// hmtx table is not large enough for the claimed
|
||||
// number of entries: invalid, do not use.
|
||||
hb_blob_destroy(mHmtxTable);
|
||||
mHmtxTable = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!mHmtxTable) {
|
||||
// If font doesn't implement GetGlyphWidth, we will be reading
|
||||
// the metrics table directly, so make sure we can load it.
|
||||
if (!LoadHmtxTable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -953,12 +1057,109 @@ gfxHarfBuzzShaper::Initialize()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxHarfBuzzShaper::LoadHmtxTable()
|
||||
{
|
||||
// Read mNumLongHMetrics from metrics-head table without caching its
|
||||
// blob, and preload/cache the metrics table.
|
||||
gfxFontEntry *entry = mFont->GetFontEntry();
|
||||
gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a'));
|
||||
if (hheaTable) {
|
||||
uint32_t len;
|
||||
const MetricsHeader* hhea =
|
||||
reinterpret_cast<const MetricsHeader*>
|
||||
(hb_blob_get_data(hheaTable, &len));
|
||||
if (len >= sizeof(MetricsHeader)) {
|
||||
mNumLongHMetrics = hhea->numOfLongMetrics;
|
||||
if (mNumLongHMetrics > 0 &&
|
||||
int16_t(hhea->metricDataFormat) == 0) {
|
||||
// no point reading metrics if number of entries is zero!
|
||||
// in that case, we won't be able to use this font
|
||||
// (this method will return FALSE below if mHmtxTable
|
||||
// is null)
|
||||
mHmtxTable = entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
|
||||
if (hb_blob_get_length(mHmtxTable) <
|
||||
mNumLongHMetrics * sizeof(LongMetric)) {
|
||||
// metrics table is not large enough for the claimed
|
||||
// number of entries: invalid, do not use.
|
||||
hb_blob_destroy(mHmtxTable);
|
||||
mHmtxTable = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!mHmtxTable) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxHarfBuzzShaper::InitializeVertical()
|
||||
{
|
||||
if (!mHmtxTable) {
|
||||
if (!LoadHmtxTable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Load vertical metrics if present in the font; if not, we'll synthesize
|
||||
// vertical glyph advances based on (horizontal) ascent/descent metrics.
|
||||
gfxFontEntry *entry = mFont->GetFontEntry();
|
||||
gfxFontEntry::AutoTable vheaTable(entry, TRUETYPE_TAG('v','h','e','a'));
|
||||
if (vheaTable) {
|
||||
uint32_t len;
|
||||
const MetricsHeader* vhea =
|
||||
reinterpret_cast<const MetricsHeader*>
|
||||
(hb_blob_get_data(vheaTable, &len));
|
||||
if (len >= sizeof(MetricsHeader)) {
|
||||
mNumLongVMetrics = vhea->numOfLongMetrics;
|
||||
if (mNumLongVMetrics > 0 &&
|
||||
int16_t(vhea->metricDataFormat) == 0) {
|
||||
mVmtxTable = entry->GetFontTable(TRUETYPE_TAG('v','m','t','x'));
|
||||
if (hb_blob_get_length(mVmtxTable) <
|
||||
mNumLongVMetrics * sizeof(LongMetric)) {
|
||||
// metrics table is not large enough for the claimed
|
||||
// number of entries: invalid, do not use.
|
||||
hb_blob_destroy(mVmtxTable);
|
||||
mVmtxTable = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For CFF fonts only, load a VORG table if present.
|
||||
if (entry->HasFontTable(TRUETYPE_TAG('C','F','F',' '))) {
|
||||
mVORGTable = entry->GetFontTable(TRUETYPE_TAG('V','O','R','G'));
|
||||
if (mVORGTable) {
|
||||
uint32_t len;
|
||||
const VORG* vorg =
|
||||
reinterpret_cast<const VORG*>(hb_blob_get_data(mVORGTable,
|
||||
&len));
|
||||
if (len < sizeof(VORG) ||
|
||||
uint16_t(vorg->majorVersion) != 1 ||
|
||||
uint16_t(vorg->minorVersion) != 0 ||
|
||||
len < sizeof(VORG) + uint16_t(vorg->numVertOriginYMetrics) *
|
||||
sizeof(VORGrec)) {
|
||||
// VORG table is an unknown version, or not large enough
|
||||
// to be valid -- discard it.
|
||||
NS_WARNING("discarding invalid VORG table");
|
||||
hb_blob_destroy(mVORGTable);
|
||||
mVORGTable = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
// some font back-ends require this in order to get proper hinted metrics
|
||||
@ -972,6 +1173,12 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aVertical) {
|
||||
if (!InitializeVertical()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const gfxFontStyle *style = mFont->GetStyle();
|
||||
|
||||
nsAutoTArray<hb_feature_t,20> features;
|
||||
@ -1007,8 +1214,11 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
bool isRightToLeft = aShapedText->IsRightToLeft();
|
||||
hb_buffer_t *buffer = hb_buffer_create();
|
||||
hb_buffer_set_unicode_funcs(buffer, sHBUnicodeFuncs);
|
||||
hb_buffer_set_direction(buffer, isRightToLeft ? HB_DIRECTION_RTL :
|
||||
HB_DIRECTION_LTR);
|
||||
|
||||
hb_buffer_set_direction(buffer,
|
||||
aVertical ? HB_DIRECTION_TTB :
|
||||
(isRightToLeft ? HB_DIRECTION_RTL :
|
||||
HB_DIRECTION_LTR));
|
||||
hb_script_t scriptTag;
|
||||
if (aShapedText->GetFlags() & gfxTextRunFactory::TEXT_USE_MATH_SCRIPT) {
|
||||
scriptTag = sMathScript;
|
||||
@ -1042,7 +1252,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
}
|
||||
|
||||
nsresult rv = SetGlyphsFromRun(aContext, aShapedText, aOffset, aLength,
|
||||
aText, buffer);
|
||||
aText, buffer, aVertical);
|
||||
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store glyphs into gfxShapedWord");
|
||||
hb_buffer_destroy(buffer);
|
||||
@ -1055,12 +1265,13 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
// for charToGlyphArray
|
||||
|
||||
nsresult
|
||||
gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
const char16_t *aText,
|
||||
hb_buffer_t *aBuffer)
|
||||
hb_buffer_t *aBuffer,
|
||||
bool aVertical)
|
||||
{
|
||||
uint32_t numGlyphs;
|
||||
const hb_glyph_info_t *ginfo = hb_buffer_get_glyph_infos(aBuffer, &numGlyphs);
|
||||
@ -1092,9 +1303,13 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
int32_t glyphStart = 0; // looking for a clump that starts at this glyph
|
||||
int32_t charStart = 0; // and this char index within the range of the run
|
||||
|
||||
bool roundX;
|
||||
bool roundY;
|
||||
aContext->GetRoundOffsetsToPixels(&roundX, &roundY);
|
||||
bool roundI;
|
||||
bool roundB;
|
||||
if (aVertical) {
|
||||
aContext->GetRoundOffsetsToPixels(&roundB, &roundI);
|
||||
} else {
|
||||
aContext->GetRoundOffsetsToPixels(&roundI, &roundB);
|
||||
}
|
||||
|
||||
int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
@ -1114,10 +1329,10 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
//
|
||||
// The value of the residual is the part of the desired distance that has
|
||||
// not been included in integer offsets.
|
||||
hb_position_t x_residual = 0;
|
||||
hb_position_t residual = 0;
|
||||
|
||||
// keep track of y-position to set glyph offsets if needed
|
||||
nscoord yPos = 0;
|
||||
nscoord bPos = 0;
|
||||
|
||||
const hb_glyph_position_t *posInfo =
|
||||
hb_buffer_get_glyph_positions(aBuffer, nullptr);
|
||||
@ -1212,28 +1427,43 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
continue;
|
||||
}
|
||||
|
||||
hb_position_t x_offset = posInfo[glyphStart].x_offset;
|
||||
hb_position_t x_advance = posInfo[glyphStart].x_advance;
|
||||
nscoord xOffset, advance;
|
||||
if (roundX) {
|
||||
xOffset =
|
||||
appUnitsPerDevUnit * FixedToIntRound(x_offset + x_residual);
|
||||
// Desired distance from the base glyph to the next reference point.
|
||||
hb_position_t width = x_advance - x_offset;
|
||||
int intWidth = FixedToIntRound(width);
|
||||
x_residual = width - FloatToFixed(intWidth);
|
||||
advance = appUnitsPerDevUnit * intWidth + xOffset;
|
||||
// HarfBuzz gives us physical x- and y-coordinates, but we will store
|
||||
// them as logical inline- and block-direction values in the textrun.
|
||||
|
||||
hb_position_t i_offset, i_advance; // inline-direction offset/advance
|
||||
hb_position_t b_offset, b_advance; // block-direction offset/advance
|
||||
if (aVertical) {
|
||||
i_offset = posInfo[glyphStart].y_offset;
|
||||
i_advance = posInfo[glyphStart].y_advance;
|
||||
b_offset = posInfo[glyphStart].x_offset;
|
||||
b_advance = posInfo[glyphStart].x_advance;
|
||||
} else {
|
||||
xOffset = floor(hb2appUnits * x_offset + 0.5);
|
||||
advance = floor(hb2appUnits * x_advance + 0.5);
|
||||
i_offset = posInfo[glyphStart].x_offset;
|
||||
i_advance = posInfo[glyphStart].x_advance;
|
||||
b_offset = posInfo[glyphStart].y_offset;
|
||||
b_advance = posInfo[glyphStart].y_advance;
|
||||
}
|
||||
|
||||
nscoord iOffset, advance;
|
||||
if (roundI) {
|
||||
iOffset =
|
||||
appUnitsPerDevUnit * FixedToIntRound(i_offset + residual);
|
||||
// Desired distance from the base glyph to the next reference point.
|
||||
hb_position_t width = i_advance - i_offset;
|
||||
int intWidth = FixedToIntRound(width);
|
||||
residual = width - FloatToFixed(intWidth);
|
||||
advance = appUnitsPerDevUnit * intWidth + iOffset;
|
||||
} else {
|
||||
iOffset = floor(hb2appUnits * i_offset + 0.5);
|
||||
advance = floor(hb2appUnits * i_advance + 0.5);
|
||||
}
|
||||
// Check if it's a simple one-to-one mapping
|
||||
if (glyphsInClump == 1 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
charGlyphs[baseCharIndex].IsClusterStart() &&
|
||||
xOffset == 0 &&
|
||||
posInfo[glyphStart].y_offset == 0 && yPos == 0)
|
||||
iOffset == 0 && b_offset == 0 &&
|
||||
b_advance == 0 && bPos == 0)
|
||||
{
|
||||
charGlyphs[baseCharIndex].SetSimpleGlyph(advance,
|
||||
ginfo[glyphStart].codepoint);
|
||||
@ -1247,41 +1477,49 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
|
||||
detailedGlyphs.AppendElement();
|
||||
details->mGlyphID = ginfo[glyphStart].codepoint;
|
||||
|
||||
details->mXOffset = xOffset;
|
||||
details->mXOffset = iOffset;
|
||||
details->mAdvance = advance;
|
||||
|
||||
hb_position_t y_offset = posInfo[glyphStart].y_offset;
|
||||
details->mYOffset = yPos -
|
||||
(roundY ? appUnitsPerDevUnit * FixedToIntRound(y_offset)
|
||||
: floor(hb2appUnits * y_offset + 0.5));
|
||||
details->mYOffset = bPos -
|
||||
(roundB ? appUnitsPerDevUnit * FixedToIntRound(b_offset)
|
||||
: floor(hb2appUnits * b_offset + 0.5));
|
||||
|
||||
hb_position_t y_advance = posInfo[glyphStart].y_advance;
|
||||
if (y_advance != 0) {
|
||||
yPos -=
|
||||
roundY ? appUnitsPerDevUnit * FixedToIntRound(y_advance)
|
||||
: floor(hb2appUnits * y_advance + 0.5);
|
||||
if (b_advance != 0) {
|
||||
bPos -=
|
||||
roundB ? appUnitsPerDevUnit * FixedToIntRound(b_advance)
|
||||
: floor(hb2appUnits * b_advance + 0.5);
|
||||
}
|
||||
if (++glyphStart >= glyphEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
x_offset = posInfo[glyphStart].x_offset;
|
||||
x_advance = posInfo[glyphStart].x_advance;
|
||||
if (roundX) {
|
||||
xOffset = appUnitsPerDevUnit *
|
||||
FixedToIntRound(x_offset + x_residual);
|
||||
if (aVertical) {
|
||||
i_offset = posInfo[glyphStart].y_offset;
|
||||
i_advance = posInfo[glyphStart].y_advance;
|
||||
b_offset = posInfo[glyphStart].x_offset;
|
||||
b_advance = posInfo[glyphStart].x_advance;
|
||||
} else {
|
||||
i_offset = posInfo[glyphStart].x_offset;
|
||||
i_advance = posInfo[glyphStart].x_advance;
|
||||
b_offset = posInfo[glyphStart].y_offset;
|
||||
b_advance = posInfo[glyphStart].y_advance;
|
||||
}
|
||||
|
||||
if (roundI) {
|
||||
iOffset = appUnitsPerDevUnit *
|
||||
FixedToIntRound(i_offset + residual);
|
||||
// Desired distance to the next reference point. The
|
||||
// residual is considered here, and includes the residual
|
||||
// from the base glyph offset and subsequent advances, so
|
||||
// that the distance from the base glyph is optimized
|
||||
// rather than the distance from combining marks.
|
||||
x_advance += x_residual;
|
||||
int intAdvance = FixedToIntRound(x_advance);
|
||||
x_residual = x_advance - FloatToFixed(intAdvance);
|
||||
i_advance += residual;
|
||||
int intAdvance = FixedToIntRound(i_advance);
|
||||
residual = i_advance - FloatToFixed(intAdvance);
|
||||
advance = appUnitsPerDevUnit * intAdvance;
|
||||
} else {
|
||||
xOffset = floor(hb2appUnits * x_offset + 0.5);
|
||||
advance = floor(hb2appUnits * x_advance + 0.5);
|
||||
iOffset = floor(hb2appUnits * i_offset + 0.5);
|
||||
advance = floor(hb2appUnits * i_advance + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ public:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
// get a given font table in harfbuzz blob form
|
||||
@ -44,11 +45,33 @@ public:
|
||||
hb_position_t GetGlyphHAdvance(gfxContext *aContext,
|
||||
hb_codepoint_t glyph) const;
|
||||
|
||||
hb_position_t GetGlyphVAdvance(gfxContext *aContext,
|
||||
hb_codepoint_t glyph) const;
|
||||
|
||||
void GetGlyphVOrigin(gfxContext *aContext, hb_codepoint_t aGlyph,
|
||||
hb_position_t *aX, hb_position_t *aY) const;
|
||||
|
||||
// get harfbuzz horizontal advance in 16.16 fixed point format.
|
||||
static hb_position_t
|
||||
HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph, void *user_data);
|
||||
|
||||
// get harfbuzz vertical advance in 16.16 fixed point format.
|
||||
static hb_position_t
|
||||
HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph, void *user_data);
|
||||
|
||||
static hb_bool_t
|
||||
HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y,
|
||||
void *user_data);
|
||||
static hb_bool_t
|
||||
HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y,
|
||||
void *user_data);
|
||||
|
||||
hb_position_t GetHKerning(uint16_t aFirstGlyph,
|
||||
uint16_t aSecondGlyph) const;
|
||||
|
||||
@ -68,12 +91,13 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
nsresult SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
nsresult SetGlyphsFromRun(gfxContext *aContext,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
const char16_t *aText,
|
||||
hb_buffer_t *aBuffer);
|
||||
hb_buffer_t *aBuffer,
|
||||
bool aVertical);
|
||||
|
||||
// retrieve glyph positions, applying advance adjustments and attachments
|
||||
// returns results in appUnits
|
||||
@ -82,6 +106,9 @@ protected:
|
||||
nsTArray<nsPoint>& aPositions,
|
||||
uint32_t aAppUnitsPerDevUnit);
|
||||
|
||||
bool InitializeVertical();
|
||||
bool LoadHmtxTable();
|
||||
|
||||
// harfbuzz face object: we acquire a reference from the font entry
|
||||
// on shaper creation, and release it in our destructor
|
||||
hb_face_t *mHBFace;
|
||||
@ -99,13 +126,12 @@ protected:
|
||||
// Old-style TrueType kern table, if we're not doing GPOS kerning
|
||||
mutable hb_blob_t *mKernTable;
|
||||
|
||||
// Cached copy of the hmtx table and numLongMetrics field from hhea,
|
||||
// for use when looking up glyph metrics; initialized to 0 by the
|
||||
// constructor so we can tell it hasn't been set yet.
|
||||
// This is a signed value so that we can use -1 to indicate
|
||||
// an error (if the hhea table was not available).
|
||||
// Cached copy of the hmtx table.
|
||||
mutable hb_blob_t *mHmtxTable;
|
||||
mutable int32_t mNumLongMetrics;
|
||||
|
||||
// For vertical fonts, cached vmtx and VORG table, if present.
|
||||
mutable hb_blob_t *mVmtxTable;
|
||||
mutable hb_blob_t *mVORGTable;
|
||||
|
||||
// Cached pointer to cmap subtable to be used for char-to-glyph mapping.
|
||||
// This comes from GetFontTablePtr; if it is non-null, our destructor
|
||||
@ -115,6 +141,15 @@ protected:
|
||||
mutable uint32_t mSubtableOffset;
|
||||
mutable uint32_t mUVSTableOffset;
|
||||
|
||||
// Cached copy of numLongMetrics field from the hhea table,
|
||||
// for use when looking up glyph metrics; initialized to 0 by the
|
||||
// constructor so we can tell it hasn't been set yet.
|
||||
// This is a signed value so that we can use -1 to indicate
|
||||
// an error (if the hhea table was not available).
|
||||
mutable int32_t mNumLongHMetrics;
|
||||
// Similarly for vhea if it's a vertical font.
|
||||
mutable int32_t mNumLongVMetrics;
|
||||
|
||||
// Whether the font implements GetGlyph, or we should read tables
|
||||
// directly
|
||||
bool mUseFontGetGlyph;
|
||||
@ -123,6 +158,7 @@ protected:
|
||||
bool mUseFontGlyphWidths;
|
||||
|
||||
bool mInitialized;
|
||||
bool mVerticalInitialized;
|
||||
};
|
||||
|
||||
#endif /* GFX_HARFBUZZSHAPER_H */
|
||||
|
@ -124,6 +124,7 @@ gfxMacFont::ShapeText(gfxContext *aContext,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
if (!mIsValid) {
|
||||
@ -131,19 +132,22 @@ gfxMacFont::ShapeText(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout()) {
|
||||
// Currently, we don't support vertical shaping via CoreText,
|
||||
// so we ignore RequiresAATLayout if vertical is requested.
|
||||
if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout() &&
|
||||
!aVertical) {
|
||||
if (!mCoreTextShaper) {
|
||||
mCoreTextShaper = new gfxCoreTextShaper(this);
|
||||
}
|
||||
if (mCoreTextShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText)) {
|
||||
aScript, aVertical, aShapedText)) {
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
|
||||
aShapedText);
|
||||
aVertical, aShapedText);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -57,6 +57,7 @@ protected:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
void InitMetrics();
|
||||
|
@ -1240,10 +1240,13 @@ gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext,
|
||||
gfxTextRunFactory::TEXT_IS_ASCII |
|
||||
gfxTextRunFactory::TEXT_IS_PERSISTENT |
|
||||
aOrientation;
|
||||
bool vertical =
|
||||
(GetFlags() & gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT) != 0;
|
||||
gfxShapedWord *sw = aFont->GetShapedWord(aContext,
|
||||
&space, 1,
|
||||
gfxShapedWord::HashMix(0, ' '),
|
||||
MOZ_SCRIPT_LATIN,
|
||||
vertical,
|
||||
mAppUnitsPerDevUnit,
|
||||
flags,
|
||||
nullptr);
|
||||
@ -2224,7 +2227,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
const gfxTextRange& range = fontRanges[r];
|
||||
uint32_t matchedLength = range.Length();
|
||||
gfxFont *matchedFont = range.font;
|
||||
|
||||
bool vertical =
|
||||
range.orientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
|
||||
// create the glyph run for this range
|
||||
if (matchedFont && mStyle.noFallbackVariantFeatures) {
|
||||
// common case - just do glyph layout and record the
|
||||
@ -2236,7 +2240,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
aString + runStart,
|
||||
aOffset + runStart,
|
||||
matchedLength,
|
||||
aRunScript)) {
|
||||
aRunScript,
|
||||
vertical)) {
|
||||
// glyph layout failed! treat as missing glyphs
|
||||
matchedFont = nullptr;
|
||||
}
|
||||
@ -2275,7 +2280,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
aString + runStart,
|
||||
aOffset + runStart,
|
||||
matchedLength,
|
||||
aRunScript)) {
|
||||
aRunScript,
|
||||
vertical)) {
|
||||
// glyph layout failed! treat as missing glyphs
|
||||
matchedFont = nullptr;
|
||||
}
|
||||
@ -2319,7 +2325,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
|
||||
aString + runStart,
|
||||
aOffset + runStart,
|
||||
matchedLength,
|
||||
aRunScript)) {
|
||||
aRunScript,
|
||||
vertical)) {
|
||||
// glyph layout failed! treat as missing glyphs
|
||||
matchedFont = nullptr;
|
||||
}
|
||||
|
@ -570,6 +570,9 @@ hb_font_funcs_set_glyph_contour_point_func
|
||||
hb_font_funcs_set_glyph_func
|
||||
hb_font_funcs_set_glyph_h_advance_func
|
||||
hb_font_funcs_set_glyph_h_kerning_func
|
||||
hb_font_funcs_set_glyph_h_origin_func
|
||||
hb_font_funcs_set_glyph_v_origin_func
|
||||
hb_font_funcs_set_glyph_v_advance_func
|
||||
hb_font_set_funcs
|
||||
hb_font_set_ppem
|
||||
hb_font_set_scale
|
||||
|
Loading…
x
Reference in New Issue
Block a user