From 5cadcfeab8ffaafa67b4b225da815480f4258a92 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 16 Sep 2014 12:25:45 +0100 Subject: [PATCH] bug 1057331 - add orientation flags to gfxShapedText/gfxTextRun and to glyph runs within the text run, and split glyph runs on orientation changes. r=jdaggett --- gfx/thebes/gfxFont.cpp | 59 ++++++----- gfx/thebes/gfxFont.h | 70 ++++++++----- gfx/thebes/gfxTextRun.cpp | 106 ++++++++++++++------ gfx/thebes/gfxTextRun.h | 12 ++- layout/base/nsLayoutUtils.cpp | 35 +++++++ layout/generic/nsTextRunTransformations.cpp | 2 +- layout/mathml/nsMathMLChar.cpp | 4 +- 7 files changed, 207 insertions(+), 81 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index d161272a698b..8b1ed7de4982 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -2573,7 +2573,8 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext, uint32_t flags = aTextRun->GetFlags(); flags &= (gfxTextRunFactory::TEXT_IS_RTL | gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES | - gfxTextRunFactory::TEXT_USE_MATH_SCRIPT); + gfxTextRunFactory::TEXT_USE_MATH_SCRIPT | + gfxTextRunFactory::TEXT_ORIENT_MASK); if (sizeof(T) == sizeof(uint8_t)) { flags |= gfxTextRunFactory::TEXT_IS_8BIT; } @@ -2642,8 +2643,13 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext, if (boundary) { // 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; + } if (!aTextRun->SetSpaceGlyphIfSimple(this, aContext, - aRunStart + i, ch)) + aRunStart + i, ch, + orientation)) { static const uint8_t space = ' '; gfxShapedWord *sw = @@ -2707,24 +2713,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext, uint32_t aRunLength, int32_t aRunScript); -bool -gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, - gfxTextRun *aTextRun, - const uint8_t *aText, - uint32_t aOffset, - uint32_t aLength, - uint8_t aMatchType, - int32_t aScript, - bool aSyntheticLower, - bool aSyntheticUpper) -{ - NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast(aText), - aLength); - return InitFakeSmallCapsRun(aContext, aTextRun, unicodeString.get(), - aOffset, aLength, aMatchType, aScript, - aSyntheticLower, aSyntheticUpper); -} - +template<> bool gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, gfxTextRun *aTextRun, @@ -2732,6 +2721,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, uint32_t aOffset, uint32_t aLength, uint8_t aMatchType, + uint16_t aOrientation, int32_t aScript, bool aSyntheticLower, bool aSyntheticUpper) @@ -2768,7 +2758,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, if (IsClusterExtender(ch)) { chAction = runAction; } else { - if (ch != ToUpperCase(ch) || mozilla::unicode::SpecialUpper(ch)) { + if (ch != ToUpperCase(ch) || SpecialUpper(ch)) { // ch is lower case chAction = (aSyntheticLower ? kUppercaseReduce : kNoChange); } else if (ch != ToLowerCase(ch)) { @@ -2801,7 +2791,8 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, switch (runAction) { case kNoChange: // just use the current font and the existing string - aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, true); + aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, true, + aOrientation); if (!f->SplitAndInitTextRun(aContext, aTextRun, aText + runStart, aOffset + runStart, runLength, @@ -2842,7 +2833,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, tempRun = gfxTextRun::Create(¶ms, convertedString.Length(), aTextRun->GetFontGroup(), 0); - tempRun->AddGlyphRun(f, aMatchType, 0, true); + tempRun->AddGlyphRun(f, aMatchType, 0, true, aOrientation); if (!f->SplitAndInitTextRun(aContext, tempRun, convertedString.BeginReading(), 0, convertedString.Length(), @@ -2861,7 +2852,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, } } else { aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart, - true); + true, aOrientation); if (!f->SplitAndInitTextRun(aContext, aTextRun, convertedString.BeginReading(), aOffset + runStart, runLength, @@ -2884,6 +2875,26 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, return ok; } +template<> +bool +gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, + gfxTextRun *aTextRun, + const uint8_t *aText, + uint32_t aOffset, + uint32_t aLength, + uint8_t aMatchType, + uint16_t aOrientation, + int32_t aScript, + bool aSyntheticLower, + bool aSyntheticUpper) +{ + NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast(aText), + aLength); + return InitFakeSmallCapsRun(aContext, aTextRun, unicodeString.get(), + aOffset, aLength, aMatchType, aOrientation, + aScript, aSyntheticLower, aSyntheticUpper); +} + already_AddRefed gfxFont::GetSmallCapsFont() { diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 921b5e1f7c33..1bee7e5a46ae 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -207,16 +207,19 @@ struct gfxTextRange { kSystemFallback = 0x0004 }; gfxTextRange(uint32_t aStart, uint32_t aEnd, - gfxFont* aFont, uint8_t aMatchType) + gfxFont* aFont, uint8_t aMatchType, + uint16_t aOrientation) : start(aStart), end(aEnd), font(aFont), - matchType(aMatchType) + matchType(aMatchType), + orientation(aOrientation) { } uint32_t Length() const { return end - start; } uint32_t start, end; nsRefPtr font; uint8_t matchType; + uint16_t orientation; }; @@ -438,8 +441,7 @@ public: enum { CACHE_TEXT_FLAGS = 0xF0000000, USER_TEXT_FLAGS = 0x0FFF0000, - PLATFORM_TEXT_FLAGS = 0x0000F000, - TEXTRUN_TEXT_FLAGS = 0x00000FFF, + TEXTRUN_TEXT_FLAGS = 0x0000FFFF, SETTABLE_FLAGS = CACHE_TEXT_FLAGS | USER_TEXT_FLAGS, /** @@ -503,6 +505,31 @@ public: */ TEXT_HIDE_CONTROL_CHARACTERS = 0x0400, + /** + * Field for orientation of the textrun and glyphs within it. + * Possible values of the TEXT_ORIENT_MASK field: + * TEXT_ORIENT_HORIZONTAL + * TEXT_ORIENT_VERTICAL_UPRIGHT + * TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT + * TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT + * TEXT_ORIENT_VERTICAL_MIXED + * For all VERTICAL settings, the x and y coordinates of glyph + * positions are exchanged, so that simple advances are vertical. + * + * The MIXED value indicates vertical textRuns for which the CSS + * text-orientation property is 'mixed', but is never used for + * individual glyphRuns; it will be resolved to either UPRIGHT + * or SIDEWAYS_RIGHT according to the UTR50 properties of the + * characters, and separate glyphRuns created for the resulting + * glyph orientations. + */ + TEXT_ORIENT_MASK = 0xF000, + TEXT_ORIENT_HORIZONTAL = 0x0000, + TEXT_ORIENT_VERTICAL_UPRIGHT = 0x1000, + TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT = 0x2000, + TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT = 0x4000, + TEXT_ORIENT_VERTICAL_MIXED = 0x8000, + /** * nsTextFrameThebes sets these, but they're defined here rather than * in nsTextFrameUtils.h because ShapedWord creation/caching also needs @@ -904,6 +931,11 @@ public: return mFlags; } + bool IsVertical() const { + return (GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK) != + gfxTextRunFactory::TEXT_ORIENT_HORIZONTAL; + } + bool IsRightToLeft() const { return (GetFlags() & gfxTextRunFactory::TEXT_IS_RTL) != 0; } @@ -1561,25 +1593,17 @@ public: return mFontEntry->GetUVSGlyph(aCh, aVS); } - bool InitFakeSmallCapsRun(gfxContext *aContext, - gfxTextRun *aTextRun, - const uint8_t *aText, - uint32_t aOffset, - uint32_t aLength, - uint8_t aMatchType, - int32_t aScript, - bool aSyntheticLower, - bool aSyntheticUpper); - - bool InitFakeSmallCapsRun(gfxContext *aContext, - gfxTextRun *aTextRun, - const char16_t *aText, - uint32_t aOffset, - uint32_t aLength, - uint8_t aMatchType, - int32_t aScript, - bool aSyntheticLower, - bool aSyntheticUpper); + template + bool InitFakeSmallCapsRun(gfxContext *aContext, + gfxTextRun *aTextRun, + const T *aText, + uint32_t aOffset, + uint32_t aLength, + uint8_t aMatchType, + uint16_t aOrientation, + int32_t aScript, + bool aSyntheticLower, + bool aSyntheticUpper); // call the (virtual) InitTextRun method to do glyph generation/shaping, // limiting the length of text passed by processing the run in multiple diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 0deb4736a21c..05eee26bb40d 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -980,9 +980,12 @@ gfxTextRun::FindFirstGlyphRunContaining(uint32_t aOffset) nsresult gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, - uint32_t aUTF16Offset, bool aForceNewRun) + uint32_t aUTF16Offset, bool aForceNewRun, + uint16_t aOrientation) { NS_ASSERTION(aFont, "adding glyph run for null font!"); + NS_ASSERTION(aOrientation != gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED, + "mixed orientation should have been resolved"); if (!aFont) { return NS_OK; } @@ -995,7 +998,8 @@ gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, // Don't append a run if the font is already the one we want if (lastGlyphRun->mFont == aFont && - lastGlyphRun->mMatchType == aMatchType) + lastGlyphRun->mMatchType == aMatchType && + lastGlyphRun->mOrientation == aOrientation) { return NS_OK; } @@ -1009,7 +1013,8 @@ gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, // adjacent runs with the same font if (numGlyphRuns > 1 && mGlyphRuns[numGlyphRuns - 2].mFont == aFont && - mGlyphRuns[numGlyphRuns - 2].mMatchType == aMatchType) + mGlyphRuns[numGlyphRuns - 2].mMatchType == aMatchType && + mGlyphRuns[numGlyphRuns - 2].mOrientation == aOrientation) { mGlyphRuns.TruncateLength(numGlyphRuns - 1); return NS_OK; @@ -1017,6 +1022,7 @@ gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, lastGlyphRun->mFont = aFont; lastGlyphRun->mMatchType = aMatchType; + lastGlyphRun->mOrientation = aOrientation; return NS_OK; } } @@ -1030,6 +1036,7 @@ gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, glyphRun->mFont = aFont; glyphRun->mCharacterOffset = aUTF16Offset; glyphRun->mMatchType = aMatchType; + glyphRun->mOrientation = aOrientation; return NS_OK; } @@ -1047,9 +1054,10 @@ gfxTextRun::SortGlyphRuns() mGlyphRuns.Clear(); uint32_t i, count = runs.Length(); for (i = 0; i < count; ++i) { - // a GlyphRun with the same font as the previous GlyphRun can just - // be skipped; the last GlyphRun will cover its character range. - if (i == 0 || runs[i].mFont != runs[i - 1].mFont) { + // a GlyphRun with the same font and orientation as the previous can + // just be skipped; the last GlyphRun will cover its character range. + if (i == 0 || runs[i].mFont != runs[i - 1].mFont || + runs[i].mOrientation != runs[i - 1].mOrientation) { mGlyphRuns.AppendElement(runs[i]); // If two fonts have the same character offset, Sort() will have // randomized the order. @@ -1201,7 +1209,8 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, "Ended font run in the middle of a cluster"); nsresult rv = AddGlyphRun(font, iter.GetGlyphRun()->mMatchType, - start - aStart + aDest, false); + start - aStart + aDest, false, + iter.GetGlyphRun()->mOrientation); if (NS_FAILED(rv)) return; } @@ -1218,32 +1227,37 @@ gfxTextRun::ClearGlyphsAndCharacters() void gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, - uint32_t aCharIndex) + uint32_t aCharIndex, uint16_t aOrientation) { - if (SetSpaceGlyphIfSimple(aFont, aContext, aCharIndex, ' ')) { + if (SetSpaceGlyphIfSimple(aFont, aContext, aCharIndex, ' ', + aOrientation)) { return; } aFont->InitWordCache(); static const uint8_t space = ' '; + uint32_t flags = gfxTextRunFactory::TEXT_IS_8BIT | + gfxTextRunFactory::TEXT_IS_ASCII | + gfxTextRunFactory::TEXT_IS_PERSISTENT | + aOrientation; gfxShapedWord *sw = aFont->GetShapedWord(aContext, &space, 1, gfxShapedWord::HashMix(0, ' '), MOZ_SCRIPT_LATIN, mAppUnitsPerDevUnit, - gfxTextRunFactory::TEXT_IS_8BIT | - gfxTextRunFactory::TEXT_IS_ASCII | - gfxTextRunFactory::TEXT_IS_PERSISTENT, + flags, nullptr); if (sw) { - AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false); + AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false, + aOrientation); CopyGlyphDataFrom(sw, aCharIndex); } } bool gfxTextRun::SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext, - uint32_t aCharIndex, char16_t aSpaceChar) + uint32_t aCharIndex, char16_t aSpaceChar, + uint16_t aOrientation) { uint32_t spaceGlyph = aFont->GetSpaceGlyph(); if (!spaceGlyph || !CompressedGlyph::IsSimpleGlyphID(spaceGlyph)) { @@ -1256,7 +1270,8 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext, return false; } - AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false); + AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false, + aOrientation); CompressedGlyph g; g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph); if (aSpaceChar == ' ') { @@ -1798,18 +1813,24 @@ gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags) return nullptr; } + uint16_t orientation = aFlags & TEXT_ORIENT_MASK; + if (orientation == TEXT_ORIENT_VERTICAL_MIXED) { + orientation = TEXT_ORIENT_VERTICAL_UPRIGHT; + } + gfxFont *font = GetFontAt(0); if (MOZ_UNLIKELY(GetStyle()->size == 0)) { // Short-circuit for size-0 fonts, as Windows and ATSUI can't handle // them, and always create at least size 1 fonts, i.e. they still // render something for size 0 fonts. - textRun->AddGlyphRun(font, gfxTextRange::kFontGroup, 0, false); + textRun->AddGlyphRun(font, gfxTextRange::kFontGroup, 0, false, + orientation); } else { if (font->GetSpaceGlyph()) { // Normally, the font has a cached space glyph, so we can avoid // the cost of calling FindFontForChar. - textRun->SetSpaceGlyph(font, aParams->mContext, 0); + textRun->SetSpaceGlyph(font, aParams->mContext, 0, orientation); } else { // In case the primary font doesn't have (bug 970891), // find one that does. @@ -1817,7 +1838,8 @@ gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags) nsRefPtr spaceFont = FindFontForChar(' ', 0, MOZ_SCRIPT_LATIN, nullptr, &matchType); if (spaceFont) { - textRun->SetSpaceGlyph(spaceFont, aParams->mContext, 0); + textRun->SetSpaceGlyph(spaceFont, aParams->mContext, 0, + orientation); } } } @@ -1838,7 +1860,12 @@ gfxFontGroup::MakeBlankTextRun(uint32_t aLength, return nullptr; } - textRun->AddGlyphRun(GetFontAt(0), gfxTextRange::kFontGroup, 0, false); + uint16_t orientation = aFlags & TEXT_ORIENT_MASK; + if (orientation == TEXT_ORIENT_VERTICAL_MIXED) { + orientation = TEXT_ORIENT_VERTICAL_UPRIGHT; + } + textRun->AddGlyphRun(GetFontAt(0), gfxTextRange::kFontGroup, 0, false, + orientation); return textRun; } @@ -2124,7 +2151,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, uint32_t runStart = 0; nsAutoTArray fontRanges; - ComputeRanges(fontRanges, aString, aLength, aRunScript); + ComputeRanges(fontRanges, aString, aLength, aRunScript, + aTextRun->GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK); uint32_t numRanges = fontRanges.Length(); for (uint32_t r = 0; r < numRanges; r++) { @@ -2137,7 +2165,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, // common case - just do glyph layout and record the // resulting positioned glyphs aTextRun->AddGlyphRun(matchedFont, range.matchType, - aOffset + runStart, (matchedLength > 0)); + aOffset + runStart, (matchedLength > 0), + range.orientation); if (!matchedFont->SplitAndInitTextRun(aContext, aTextRun, aString + runStart, aOffset + runStart, @@ -2175,7 +2204,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, nsRefPtr subSuperFont = matchedFont->GetSubSuperscriptFont(aTextRun->GetAppUnitsPerDevUnit()); aTextRun->AddGlyphRun(subSuperFont, range.matchType, - aOffset + runStart, (matchedLength > 0)); + aOffset + runStart, (matchedLength > 0), + range.orientation); if (!subSuperFont->SplitAndInitTextRun(aContext, aTextRun, aString + runStart, aOffset + runStart, @@ -2197,6 +2227,7 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, aOffset + runStart, matchedLength, range.matchType, + range.orientation, aRunScript, syntheticLower, syntheticUpper)) { @@ -2217,7 +2248,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, // do glyph layout and record the resulting positioned glyphs aTextRun->AddGlyphRun(matchedFont, range.matchType, - aOffset + runStart, (matchedLength > 0)); + aOffset + runStart, (matchedLength > 0), + range.orientation); if (!matchedFont->SplitAndInitTextRun(aContext, aTextRun, aString + runStart, aOffset + runStart, @@ -2229,7 +2261,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext, } } else { aTextRun->AddGlyphRun(mainFont, gfxTextRange::kFontGroup, - aOffset + runStart, (matchedLength > 0)); + aOffset + runStart, (matchedLength > 0), + range.orientation); } if (!matchedFont) { @@ -2483,7 +2516,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, template void gfxFontGroup::ComputeRanges(nsTArray& aRanges, const T *aString, uint32_t aLength, - int32_t aRunScript) + int32_t aRunScript, uint16_t aOrientation) { NS_ASSERTION(aRanges.Length() == 0, "aRanges must be initially empty"); NS_ASSERTION(aLength > 0, "don't call ComputeRanges for zero-length text"); @@ -2536,19 +2569,36 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, prevCh = ch; + uint16_t orient = aOrientation; + if (aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED) { + // For CSS text-orientation:mixed, we need to resolve orientation + // on a per-character basis using the UTR50 orientation property. + switch (GetVerticalOrientation(ch)) { + case VERTICAL_ORIENTATION_U: + case VERTICAL_ORIENTATION_Tr: + case VERTICAL_ORIENTATION_Tu: + orient = TEXT_ORIENT_VERTICAL_UPRIGHT; + break; + case VERTICAL_ORIENTATION_R: + orient = TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT; + break; + } + } + if (lastRangeIndex == -1) { // first char ==> make a new range - aRanges.AppendElement(gfxTextRange(0, 1, font, matchType)); + aRanges.AppendElement(gfxTextRange(0, 1, font, matchType, orient)); lastRangeIndex++; prevFont = font; } else { // if font has changed, make a new range gfxTextRange& prevRange = aRanges[lastRangeIndex]; - if (prevRange.font != font || prevRange.matchType != matchType) { + if (prevRange.font != font || prevRange.matchType != matchType || + prevRange.orientation != orient) { // close out the previous range prevRange.end = origI; aRanges.AppendElement(gfxTextRange(origI, i + 1, - font, matchType)); + font, matchType, orient)); lastRangeIndex++; // update prevFont for the next match, *unless* we switched diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index cccf2fcc9c13..06e5f12d2c32 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -411,6 +411,7 @@ public: nsRefPtr mFont; // never null uint32_t mCharacterOffset; // into original UTF16 string uint8_t mMatchType; + uint16_t mOrientation; // gfxTextRunFactory::TEXT_ORIENT_* value }; class GlyphRunIterator { @@ -467,7 +468,8 @@ public: * TextRun. */ nsresult AddGlyphRun(gfxFont *aFont, uint8_t aMatchType, - uint32_t aStartCharIndex, bool aForceNewRun); + uint32_t aStartCharIndex, bool aForceNewRun, + uint16_t aOrientation); void ResetGlyphRuns() { mGlyphRuns.Clear(); } void SortGlyphRuns(); void SanitizeGlyphRuns(); @@ -480,7 +482,8 @@ public: // clean out results from shaping in progress, used for fallback scenarios void ClearGlyphsAndCharacters(); - void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex); + void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex, + uint16_t aOrientation); // Set the glyph data for the given character index to the font's // space glyph, IF this can be done as a "simple" glyph record @@ -496,7 +499,8 @@ public: // if it returns false, the caller needs to fall back to some other // means to create the necessary (detailed) glyph data. bool SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext, - uint32_t aCharIndex, char16_t aSpaceChar); + uint32_t aCharIndex, char16_t aSpaceChar, + uint16_t aOrientation); // Record the positions of specific characters that layout may need to // detect in the textrun, even though it doesn't have an explicit copy @@ -865,7 +869,7 @@ public: template void ComputeRanges(nsTArray& mRanges, const T *aString, uint32_t aLength, - int32_t aRunScript); + int32_t aRunScript, uint16_t aOrientation); gfxUserFontSet* GetUserFontSet(); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 61bbd6f8abb6..dce382581f9a 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5632,6 +5632,41 @@ nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext, default: break; } + WritingMode wm(aStyleContext->StyleVisibility()); + if (wm.IsVertical()) { + switch (aStyleText->mTextOrientation) { + case NS_STYLE_TEXT_ORIENTATION_MIXED: + result |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED; + break; + case NS_STYLE_TEXT_ORIENTATION_UPRIGHT: + result |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT; + break; + case NS_STYLE_TEXT_ORIENTATION_SIDEWAYS: + // This should depend on writing mode vertical-lr vs vertical-rl, + // but until we support SIDEWAYS_LEFT, we'll treat this the same + // as SIDEWAYS_RIGHT and simply fall through. + /* + if (wm.IsVerticalLR()) { + result |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT; + } else { + result |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT; + } + break; + */ + case NS_STYLE_TEXT_ORIENTATION_SIDEWAYS_RIGHT: + result |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT; + break; + case NS_STYLE_TEXT_ORIENTATION_SIDEWAYS_LEFT: + // Not yet supported, so fall through to the default (error) case. + /* + result |= gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT; + break; + */ + default: + NS_NOTREACHED("unknown text-orientation"); + break; + } + } return result; } diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index 95feb300d962..f43d100da7e5 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -133,7 +133,7 @@ MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc, while (iter.NextRun()) { gfxTextRun::GlyphRun* run = iter.GetGlyphRun(); nsresult rv = aDest->AddGlyphRun(run->mFont, run->mMatchType, - offset, false); + offset, false, run->mOrientation); if (NS_FAILED(rv)) return; diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 5f2c1ada2507..7a76d2bce6c1 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -553,7 +553,9 @@ nsOpenTypeTable::MakeTextRun(gfxContext* aThebesContext, }; gfxTextRun* textRun = gfxTextRun::Create(¶ms, 1, aFontGroup, 0); textRun->AddGlyphRun(aFontGroup->GetFontAt(0), gfxTextRange::kFontGroup, 0, - false); + false, gfxTextRunFactory::TEXT_ORIENT_HORIZONTAL); + // We don't care about CSS writing mode here; + // math runs are assumed to be horizontal. gfxTextRun::DetailedGlyph detailedGlyph; detailedGlyph.mGlyphID = aGlyph.glyphID; detailedGlyph.mAdvance =