--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -653,20 +653,19 @@ ContentEventHandler::AppendFontRanges(Fo
next = static_cast<nsTextFrame*>(curr->GetNextContinuation());
while (next && next->GetTextRun(nsTextFrame::eInflated) == textRun) {
frameXPEnd = std::min(next->GetContentEnd(), aXPEndOffset);
next = frameXPEnd < aXPEndOffset ?
static_cast<nsTextFrame*>(next->GetNextContinuation()) : nullptr;
}
}
- uint32_t skipStart = iter.ConvertOriginalToSkipped(frameXPStart);
- uint32_t skipEnd = iter.ConvertOriginalToSkipped(frameXPEnd);
- gfxTextRun::GlyphRunIterator runIter(
- textRun, skipStart, skipEnd - skipStart);
+ gfxTextRun::Range skipRange(iter.ConvertOriginalToSkipped(frameXPStart),
+ iter.ConvertOriginalToSkipped(frameXPEnd));
+ gfxTextRun::GlyphRunIterator runIter(textRun, skipRange);
int32_t lastXPEndOffset = frameXPStart;
while (runIter.NextRun()) {
gfxFont* font = runIter.GetGlyphRun()->mFont.get();
int32_t startXPOffset =
iter.ConvertSkippedToOriginal(runIter.GetStringStart());
// It is possible that the first glyph run has exceeded the frame,
// because the whole frame is filled by skipped chars.
if (startXPOffset >= frameXPEnd) {
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -76,17 +76,17 @@ private:
return flags;
}
nsAutoPtr<gfxTextRun> mTextRun;
};
class StubPropertyProvider : public gfxTextRun::PropertyProvider {
public:
- virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
+ virtual void GetHyphenationBreaks(gfxTextRun::Range aRange,
bool* aBreakBefore) {
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
}
virtual int8_t GetHyphensOption() {
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
return NS_STYLE_HYPHENS_NONE;
}
virtual gfxFloat GetHyphenWidth() {
@@ -96,18 +96,17 @@ public:
virtual already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget() {
NS_ERROR("This shouldn't be called because we never enable hyphens");
return nullptr;
}
virtual uint32_t GetAppUnitsPerDevUnit() {
NS_ERROR("This shouldn't be called because we never enable hyphens");
return 60;
}
- virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
- Spacing* aSpacing) {
+ virtual void GetSpacing(gfxTextRun::Range aRange, Spacing* aSpacing) {
NS_ERROR("This shouldn't be called because we never enable spacing");
}
};
} // namespace
nsFontMetrics::nsFontMetrics()
: mDeviceContext(nullptr), mP2A(0), mTextRunRTL(false)
@@ -320,34 +319,40 @@ nsFontMetrics::GetWidth(const char* aStr
if (aLength == 0)
return 0;
if (aLength == 1 && aString[0] == ' ')
return SpaceWidth();
StubPropertyProvider provider;
AutoTextRun textRun(this, aDrawTarget, aString, aLength);
- return textRun.get() ?
- NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
+ if (textRun.get()) {
+ return NSToCoordRound(
+ textRun->GetAdvanceWidth(Range(0, aLength), &provider));
+ }
+ return 0;
}
nscoord
nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength,
DrawTarget* aDrawTarget)
{
if (aLength == 0)
return 0;
if (aLength == 1 && aString[0] == ' ')
return SpaceWidth();
StubPropertyProvider provider;
AutoTextRun textRun(this, aDrawTarget, aString, aLength);
- return textRun.get() ?
- NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0;
+ if (textRun.get()) {
+ return NSToCoordRound(
+ textRun->GetAdvanceWidth(Range(0, aLength), &provider));
+ }
+ return 0;
}
// Draw a string using this font handle on the surface passed in.
void
nsFontMetrics::DrawString(const char *aString, uint32_t aLength,
nscoord aX, nscoord aY,
nsRenderingContext *aContext)
{
@@ -355,25 +360,26 @@ nsFontMetrics::DrawString(const char *aS
return;
StubPropertyProvider provider;
AutoTextRun textRun(this, aContext->GetDrawTarget(), aString, aLength);
if (!textRun.get()) {
return;
}
gfxPoint pt(aX, aY);
+ Range range(0, aLength);
if (mTextRunRTL) {
if (mVertical) {
- pt.y += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.y += textRun->GetAdvanceWidth(range, &provider);
} else {
- pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
- textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
- &provider, nullptr, nullptr);
+ textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL,
+ range, &provider, nullptr, nullptr);
}
void
nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength,
nscoord aX, nscoord aY,
nsRenderingContext *aContext,
DrawTarget* aTextRunConstructionDrawTarget)
{
@@ -381,41 +387,42 @@ nsFontMetrics::DrawString(const char16_t
return;
StubPropertyProvider provider;
AutoTextRun textRun(this, aTextRunConstructionDrawTarget, aString, aLength);
if (!textRun.get()) {
return;
}
gfxPoint pt(aX, aY);
+ Range range(0, aLength);
if (mTextRunRTL) {
if (mVertical) {
- pt.y += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.y += textRun->GetAdvanceWidth(range, &provider);
} else {
- pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
+ pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
- textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength,
- &provider, nullptr, nullptr);
+ textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL,
+ range, &provider, nullptr, nullptr);
}
static nsBoundingMetrics
GetTextBoundingMetrics(nsFontMetrics* aMetrics, const char16_t* aString,
uint32_t aLength, mozilla::gfx::DrawTarget* aDrawTarget,
gfxFont::BoundingBoxType aType)
{
if (aLength == 0)
return nsBoundingMetrics();
StubPropertyProvider provider;
AutoTextRun textRun(aMetrics, aDrawTarget, aString, aLength);
nsBoundingMetrics m;
if (textRun.get()) {
- gfxTextRun::Metrics theMetrics =
- textRun->MeasureText(0, aLength, aType, aDrawTarget, &provider);
+ gfxTextRun::Metrics theMetrics = textRun->MeasureText(
+ gfxTextRun::Range(0, aLength), aType, aDrawTarget, &provider);
m.leftBearing = NSToCoordFloor( theMetrics.mBoundingBox.X());
m.rightBearing = NSToCoordCeil( theMetrics.mBoundingBox.XMost());
m.ascent = NSToCoordCeil( -theMetrics.mBoundingBox.Y());
m.descent = NSToCoordCeil( theMetrics.mBoundingBox.YMost());
m.width = NSToCoordRound( theMetrics.mAdvanceWidth);
}
return m;
--- a/gfx/src/nsFontMetrics.h
+++ b/gfx/src/nsFontMetrics.h
@@ -41,16 +41,17 @@ struct nsBoundingMetrics;
* the em height (for the CSS "em" unit), and we use the first Western
* font's metrics for that purpose. The platform-specific
* implementations are expected to select non-Western fonts that "fit"
* reasonably well with the Western font that is loaded at Init time.
*/
class nsFontMetrics final
{
public:
+ typedef gfxTextRun::Range Range;
typedef mozilla::gfx::DrawTarget DrawTarget;
nsFontMetrics();
NS_INLINE_DECL_REFCOUNTING(nsFontMetrics)
/**
* Initialize the font metrics. Call this after creating the font metrics.
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1938,17 +1938,17 @@ gfxFont::DrawGlyphs(gfxShapedText
// This method is mostly parallel to DrawGlyphs.
void
gfxFont::DrawEmphasisMarks(gfxTextRun* aShapedText, gfxPoint* aPt,
uint32_t aOffset, uint32_t aCount,
const EmphasisMarkDrawParams& aParams)
{
gfxFloat& inlineCoord = aParams.isVertical ? aPt->y : aPt->x;
- uint32_t markLength = aParams.mark->GetLength();
+ gfxTextRun::Range markRange(aParams.mark);
gfxFloat clusterStart = -std::numeric_limits<gfxFloat>::infinity();
bool shouldDrawEmphasisMark = false;
for (uint32_t i = 0, idx = aOffset; i < aCount; ++i, ++idx) {
if (aParams.spacing) {
inlineCoord += aParams.direction * aParams.spacing[i].mBefore;
}
if (aShapedText->IsClusterStart(idx) ||
@@ -1961,17 +1961,17 @@ gfxFont::DrawEmphasisMarks(gfxTextRun* a
inlineCoord += aParams.direction * aShapedText->GetAdvanceForGlyph(idx);
if (shouldDrawEmphasisMark &&
(i + 1 == aCount || aShapedText->IsClusterStart(idx + 1))) {
gfxFloat clusterAdvance = inlineCoord - clusterStart;
// Move the coord backward to get the needed start point.
gfxFloat delta = (clusterAdvance + aParams.advance) / 2;
inlineCoord -= delta;
aParams.mark->Draw(aParams.context, *aPt, DrawMode::GLYPH_FILL,
- 0, markLength, nullptr, nullptr, nullptr);
+ markRange, nullptr, nullptr, nullptr);
inlineCoord += delta;
shouldDrawEmphasisMark = false;
}
if (aParams.spacing) {
inlineCoord += aParams.direction * aParams.spacing[i].mAfter;
}
}
}
@@ -3182,17 +3182,18 @@ gfxFont::InitFakeSmallCapsRun(DrawTarget
} else {
nsAutoPtr<gfxTextRun> mergedRun;
mergedRun =
gfxTextRun::Create(¶ms, runLength,
aTextRun->GetFontGroup(), 0);
MergeCharactersInTextRun(mergedRun, tempRun,
charsToMergeArray.Elements(),
deletedCharsArray.Elements());
- aTextRun->CopyGlyphDataFrom(mergedRun, 0, runLength,
+ gfxTextRun::Range runRange(0, runLength);
+ aTextRun->CopyGlyphDataFrom(mergedRun, runRange,
aOffset + runStart);
}
} else {
aTextRun->AddGlyphRun(f, aMatchType, aOffset + runStart,
true, aOrientation);
if (!f->SplitAndInitTextRun(aDrawTarget, aTextRun,
convertedString.BeginReading(),
aOffset + runStart, runLength,
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -205,82 +205,81 @@ void
gfxTextRun::ReleaseFontGroup()
{
NS_ASSERTION(!mReleasedFontGroup, "doubly released!");
NS_RELEASE(mFontGroup);
mReleasedFontGroup = true;
}
bool
-gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
- uint8_t *aBreakBefore)
+gfxTextRun::SetPotentialLineBreaks(Range aRange, uint8_t *aBreakBefore)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Overflow");
+ NS_ASSERTION(aRange.end <= GetLength(), "Overflow");
uint32_t changed = 0;
uint32_t i;
- CompressedGlyph *charGlyphs = mCharacterGlyphs + aStart;
- for (i = 0; i < aLength; ++i) {
+ CompressedGlyph *charGlyphs = mCharacterGlyphs + aRange.start;
+ for (i = 0; i < aRange.Length(); ++i) {
uint8_t canBreak = aBreakBefore[i];
if (canBreak && !charGlyphs[i].IsClusterStart()) {
// This can happen ... there is no guarantee that our linebreaking rules
// align with the platform's idea of what constitutes a cluster.
canBreak = CompressedGlyph::FLAG_BREAK_TYPE_NONE;
}
changed |= charGlyphs[i].SetCanBreakBefore(canBreak);
}
return changed != 0;
}
gfxTextRun::LigatureData
-gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
- PropertyProvider *aProvider)
+gfxTextRun::ComputeLigatureData(Range aPartRange, PropertyProvider *aProvider)
{
- NS_ASSERTION(aPartStart < aPartEnd, "Computing ligature data for empty range");
- NS_ASSERTION(aPartEnd <= GetLength(), "Character length overflow");
+ NS_ASSERTION(aPartRange.start < aPartRange.end,
+ "Computing ligature data for empty range");
+ NS_ASSERTION(aPartRange.end <= GetLength(), "Character length overflow");
LigatureData result;
CompressedGlyph *charGlyphs = mCharacterGlyphs;
uint32_t i;
- for (i = aPartStart; !charGlyphs[i].IsLigatureGroupStart(); --i) {
+ for (i = aPartRange.start; !charGlyphs[i].IsLigatureGroupStart(); --i) {
NS_ASSERTION(i > 0, "Ligature at the start of the run??");
}
- result.mLigatureStart = i;
- for (i = aPartStart + 1; i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
+ result.mRange.start = i;
+ for (i = aPartRange.start + 1;
+ i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
}
- result.mLigatureEnd = i;
-
- int32_t ligatureWidth =
- GetAdvanceForGlyphs(result.mLigatureStart, result.mLigatureEnd);
+ result.mRange.end = i;
+
+ int32_t ligatureWidth = GetAdvanceForGlyphs(result.mRange);
// Count the number of started clusters we have seen
uint32_t totalClusterCount = 0;
uint32_t partClusterIndex = 0;
uint32_t partClusterCount = 0;
- for (i = result.mLigatureStart; i < result.mLigatureEnd; ++i) {
+ for (i = result.mRange.start; i < result.mRange.end; ++i) {
// Treat the first character of the ligature as the start of a
// cluster for our purposes of allocating ligature width to its
// characters.
- if (i == result.mLigatureStart || charGlyphs[i].IsClusterStart()) {
+ if (i == result.mRange.start || charGlyphs[i].IsClusterStart()) {
++totalClusterCount;
- if (i < aPartStart) {
+ if (i < aPartRange.start) {
++partClusterIndex;
- } else if (i < aPartEnd) {
+ } else if (i < aPartRange.end) {
++partClusterCount;
}
}
}
NS_ASSERTION(totalClusterCount > 0, "Ligature involving no clusters??");
result.mPartAdvance = partClusterIndex * (ligatureWidth / totalClusterCount);
result.mPartWidth = partClusterCount * (ligatureWidth / totalClusterCount);
// Any rounding errors are apportioned to the final part of the ligature,
// so that measuring all parts of a ligature and summing them is equal to
// the ligature width.
- if (aPartEnd == result.mLigatureEnd) {
+ if (aPartRange.end == result.mRange.end) {
gfxFloat allParts = totalClusterCount * (ligatureWidth / totalClusterCount);
result.mPartWidth += ligatureWidth - allParts;
}
if (partClusterCount == 0) {
// nothing to draw
result.mClipBeforePart = result.mClipAfterPart = true;
} else {
@@ -291,122 +290,128 @@ gfxTextRun::ComputeLigatureData(uint32_t
result.mClipBeforePart = partClusterIndex > 0;
// We need to clip after the part if any cluster is drawn after
// this part.
result.mClipAfterPart = partClusterIndex + partClusterCount < totalClusterCount;
}
if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) {
gfxFont::Spacing spacing;
- if (aPartStart == result.mLigatureStart) {
- aProvider->GetSpacing(aPartStart, 1, &spacing);
+ if (aPartRange.start == result.mRange.start) {
+ aProvider->GetSpacing(
+ Range(aPartRange.start, aPartRange.start + 1), &spacing);
result.mPartWidth += spacing.mBefore;
}
- if (aPartEnd == result.mLigatureEnd) {
- aProvider->GetSpacing(aPartEnd - 1, 1, &spacing);
+ if (aPartRange.end == result.mRange.end) {
+ aProvider->GetSpacing(
+ Range(aPartRange.end - 1, aPartRange.end), &spacing);
result.mPartWidth += spacing.mAfter;
}
}
return result;
}
gfxFloat
-gfxTextRun::ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd,
+gfxTextRun::ComputePartialLigatureWidth(Range aPartRange,
PropertyProvider *aProvider)
{
- if (aPartStart >= aPartEnd)
+ if (aPartRange.start >= aPartRange.end)
return 0;
- LigatureData data = ComputeLigatureData(aPartStart, aPartEnd, aProvider);
+ LigatureData data = ComputeLigatureData(aPartRange, aProvider);
return data.mPartWidth;
}
int32_t
-gfxTextRun::GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd)
+gfxTextRun::GetAdvanceForGlyphs(Range aRange)
{
int32_t advance = 0;
- for (auto i = aStart; i < aEnd; ++i) {
+ for (auto i = aRange.start; i < aRange.end; ++i) {
advance += GetAdvanceForGlyph(i);
}
return advance;
}
static void
-GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
+GetAdjustedSpacing(gfxTextRun *aTextRun, gfxTextRun::Range aRange,
gfxTextRun::PropertyProvider *aProvider,
gfxTextRun::PropertyProvider::Spacing *aSpacing)
{
- if (aStart >= aEnd)
+ if (aRange.start >= aRange.end)
return;
- aProvider->GetSpacing(aStart, aEnd - aStart, aSpacing);
+ aProvider->GetSpacing(aRange, aSpacing);
#ifdef DEBUG
// Check to see if we have spacing inside ligatures
const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
uint32_t i;
- for (i = aStart; i < aEnd; ++i) {
+ for (i = aRange.start; i < aRange.end; ++i) {
if (!charGlyphs[i].IsLigatureGroupStart()) {
- NS_ASSERTION(i == aStart || aSpacing[i - aStart].mBefore == 0,
+ NS_ASSERTION(i == aRange.start ||
+ aSpacing[i - aRange.start].mBefore == 0,
"Before-spacing inside a ligature!");
- NS_ASSERTION(i - 1 <= aStart || aSpacing[i - 1 - aStart].mAfter == 0,
+ NS_ASSERTION(i - 1 <= aRange.start ||
+ aSpacing[i - 1 - aRange.start].mAfter == 0,
"After-spacing inside a ligature!");
}
}
#endif
}
bool
-gfxTextRun::GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd,
- PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+gfxTextRun::GetAdjustedSpacingArray(Range aRange, PropertyProvider *aProvider,
+ Range aSpacingRange,
nsTArray<PropertyProvider::Spacing> *aSpacing)
{
if (!aProvider || !(mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING))
return false;
- if (!aSpacing->AppendElements(aEnd - aStart))
+ if (!aSpacing->AppendElements(aRange.Length()))
return false;
- memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing)*(aSpacingStart - aStart));
- GetAdjustedSpacing(this, aSpacingStart, aSpacingEnd, aProvider,
- aSpacing->Elements() + aSpacingStart - aStart);
- memset(aSpacing->Elements() + aSpacingEnd - aStart, 0, sizeof(gfxFont::Spacing)*(aEnd - aSpacingEnd));
+ auto spacingOffset = aSpacingRange.start - aRange.start;
+ memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing) * spacingOffset);
+ GetAdjustedSpacing(this, aSpacingRange, aProvider,
+ aSpacing->Elements() + spacingOffset);
+ memset(aSpacing->Elements() + aSpacingRange.end - aRange.start, 0,
+ sizeof(gfxFont::Spacing) * (aRange.end - aSpacingRange.end));
return true;
}
void
-gfxTextRun::ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd)
+gfxTextRun::ShrinkToLigatureBoundaries(Range* aRange)
{
- if (*aStart >= *aEnd)
+ if (aRange->start >= aRange->end)
return;
CompressedGlyph *charGlyphs = mCharacterGlyphs;
- while (*aStart < *aEnd && !charGlyphs[*aStart].IsLigatureGroupStart()) {
- ++(*aStart);
+ while (aRange->start < aRange->end &&
+ !charGlyphs[aRange->start].IsLigatureGroupStart()) {
+ ++aRange->start;
}
- if (*aEnd < GetLength()) {
- while (*aEnd > *aStart && !charGlyphs[*aEnd].IsLigatureGroupStart()) {
- --(*aEnd);
+ if (aRange->end < GetLength()) {
+ while (aRange->end > aRange->start &&
+ !charGlyphs[aRange->end].IsLigatureGroupStart()) {
+ --aRange->end;
}
}
}
void
-gfxTextRun::DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
- gfxPoint *aPt, PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+gfxTextRun::DrawGlyphs(gfxFont *aFont, Range aRange, gfxPoint *aPt,
+ PropertyProvider *aProvider, Range aSpacingRange,
TextRunDrawParams& aParams, uint16_t aOrientation)
{
AutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
- bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
- aSpacingStart, aSpacingEnd, &spacingBuffer);
+ bool haveSpacing = GetAdjustedSpacingArray(aRange, aProvider,
+ aSpacingRange, &spacingBuffer);
aParams.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr;
- aFont->Draw(this, aStart, aEnd, aPt, aParams, aOrientation);
+ aFont->Draw(this, aRange.start, aRange.end, aPt, aParams, aOrientation);
}
static void
ClipPartialLigature(const gfxTextRun* aTextRun,
gfxFloat *aStart, gfxFloat *aEnd,
gfxFloat aOrigin,
gfxTextRun::LigatureData *aLigature)
{
@@ -424,26 +429,26 @@ ClipPartialLigature(const gfxTextRun* aT
*aStart = std::max(*aStart, endEdge);
} else {
*aEnd = std::min(*aEnd, endEdge);
}
}
}
void
-gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
+gfxTextRun::DrawPartialLigature(gfxFont *aFont, Range aRange,
gfxPoint *aPt, PropertyProvider *aProvider,
TextRunDrawParams& aParams, uint16_t aOrientation)
{
- if (aStart >= aEnd) {
+ if (aRange.start >= aRange.end) {
return;
}
// Draw partial ligature. We hack this by clipping the ligature.
- LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider);
+ LigatureData data = ComputeLigatureData(aRange, aProvider);
gfxRect clipExtents = aParams.context->GetClipExtents();
gfxFloat start, end;
if (aParams.isVerticalRun) {
start = clipExtents.Y() * mAppUnitsPerDevUnit;
end = clipExtents.YMost() * mAppUnitsPerDevUnit;
ClipPartialLigature(this, &start, &end, aPt->y, &data);
} else {
start = clipExtents.X() * mAppUnitsPerDevUnit;
@@ -468,35 +473,35 @@ gfxTextRun::DrawPartialLigature(gfxFont
gfxPoint pt;
if (aParams.isVerticalRun) {
pt = gfxPoint(aPt->x, aPt->y - aParams.direction * data.mPartAdvance);
} else {
pt = gfxPoint(aPt->x - aParams.direction * data.mPartAdvance, aPt->y);
}
- DrawGlyphs(aFont, data.mLigatureStart, data.mLigatureEnd, &pt,
- aProvider, aStart, aEnd, aParams, aOrientation);
+ DrawGlyphs(aFont, data.mRange, &pt,
+ aProvider, aRange, aParams, aOrientation);
aParams.context->Restore();
if (aParams.isVerticalRun) {
aPt->y += aParams.direction * data.mPartWidth;
} else {
aPt->x += aParams.direction * data.mPartWidth;
}
}
// Returns true if a glyph run is using a font with synthetic bolding enabled,
// or a color font (COLR/SVG/sbix/CBDT), false otherwise. This is used to
// check whether the text run needs to be explicitly composited in order to
// support opacity.
static bool
-HasSyntheticBoldOrColor(gfxTextRun *aRun, uint32_t aStart, uint32_t aLength)
+HasSyntheticBoldOrColor(gfxTextRun *aRun, gfxTextRun::Range aRange)
{
- gfxTextRun::GlyphRunIterator iter(aRun, aStart, aLength);
+ gfxTextRun::GlyphRunIterator iter(aRun, aRange);
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
if (font) {
if (font->IsSyntheticBold()) {
return true;
}
gfxFontEntry* fe = font->GetFontEntry();
if (fe->TryGetSVGData(font) || fe->TryGetColorGlyphs()) {
@@ -555,22 +560,22 @@ struct BufferAlphaColor {
mContext->Restore();
}
gfxContext *mContext;
};
void
gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
- uint32_t aStart, uint32_t aLength,
+ Range aRange,
PropertyProvider *aProvider, gfxFloat *aAdvanceWidth,
gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
+ NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range");
NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH ||
!(int(aDrawMode) & int(DrawMode::GLYPH_PATH)),
"GLYPH_PATH cannot be used with GLYPH_FILL, GLYPH_STROKE or GLYPH_STROKE_UNDERNEATH");
NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH || !aCallbacks,
"callback must not be specified unless using GLYPH_PATH");
bool skipDrawing = mSkipDrawing;
if (aDrawMode == DrawMode::GLYPH_FILL) {
@@ -581,17 +586,17 @@ gfxTextRun::Draw(gfxContext *aContext, g
}
gfxFloat direction = GetDirection();
if (skipDrawing) {
// We don't need to draw anything;
// but if the caller wants advance width, we need to compute it here
if (aAdvanceWidth) {
- gfxTextRun::Metrics metrics = MeasureText(aStart, aLength,
+ gfxTextRun::Metrics metrics = MeasureText(aRange,
gfxFont::LOOSE_INK_EXTENTS,
aContext->GetDrawTarget(),
aProvider);
*aAdvanceWidth = metrics.mAdvanceWidth * direction;
}
// return without drawing
return;
@@ -600,20 +605,20 @@ gfxTextRun::Draw(gfxContext *aContext, g
// synthetic bolding draws glyphs twice ==> colors with opacity won't draw
// correctly unless first drawn without alpha
BufferAlphaColor syntheticBoldBuffer(aContext);
Color currentColor;
bool needToRestore = false;
if (aDrawMode == DrawMode::GLYPH_FILL &&
HasNonOpaqueNonTransparentColor(aContext, currentColor) &&
- HasSyntheticBoldOrColor(this, aStart, aLength)) {
+ HasSyntheticBoldOrColor(this, aRange)) {
needToRestore = true;
// measure text, use the bounding box
- gfxTextRun::Metrics metrics = MeasureText(aStart, aLength,
+ gfxTextRun::Metrics metrics = MeasureText(aRange,
gfxFont::LOOSE_INK_EXTENTS,
aContext->GetDrawTarget(),
aProvider);
metrics.mBoundingBox.MoveBy(aPt);
syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor,
GetAppUnitsPerDevUnit());
}
@@ -627,44 +632,43 @@ gfxTextRun::Draw(gfxContext *aContext, g
params.direction = direction;
params.drawMode = aDrawMode;
params.callbacks = aCallbacks;
params.runContextPaint = aContextPaint;
params.paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs;
params.dt = aContext->GetDrawTarget();
params.fontSmoothingBGColor = aContext->GetFontSmoothingBackgroundColor();
- GlyphRunIterator iter(this, aStart, aLength);
+ GlyphRunIterator iter(this, aRange);
gfxFloat advance = 0.0;
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
uint32_t start = iter.GetStringStart();
uint32_t end = iter.GetStringEnd();
- uint32_t ligatureRunStart = start;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
+ Range ligatureRange(start, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
bool drawPartial = aDrawMode == DrawMode::GLYPH_FILL ||
(aDrawMode == DrawMode::GLYPH_PATH && aCallbacks);
gfxPoint origPt = aPt;
if (drawPartial) {
- DrawPartialLigature(font, start, ligatureRunStart, &aPt,
- aProvider, params,
+ DrawPartialLigature(font, Range(start, ligatureRange.start),
+ &aPt, aProvider, params,
iter.GetGlyphRun()->mOrientation);
}
- DrawGlyphs(font, ligatureRunStart, ligatureRunEnd, &aPt,
- aProvider, ligatureRunStart, ligatureRunEnd, params,
+ DrawGlyphs(font, ligatureRange, &aPt,
+ aProvider, ligatureRange, params,
iter.GetGlyphRun()->mOrientation);
if (drawPartial) {
- DrawPartialLigature(font, ligatureRunEnd, end, &aPt,
- aProvider, params,
+ DrawPartialLigature(font, Range(ligatureRange.end, end),
+ &aPt, aProvider, params,
iter.GetGlyphRun()->mOrientation);
}
if (params.isVerticalRun) {
advance += (aPt.y - origPt.y) * params.direction;
} else {
advance += (aPt.x - origPt.x) * params.direction;
}
@@ -679,94 +683,89 @@ gfxTextRun::Draw(gfxContext *aContext, g
*aAdvanceWidth = advance;
}
}
// This method is mostly parallel to Draw().
void
gfxTextRun::DrawEmphasisMarks(gfxContext *aContext, gfxTextRun* aMark,
gfxFloat aMarkAdvance, gfxPoint aPt,
- uint32_t aStart, uint32_t aLength,
- PropertyProvider* aProvider)
+ Range aRange, PropertyProvider* aProvider)
{
- MOZ_ASSERT(aStart + aLength <= GetLength());
+ MOZ_ASSERT(aRange.end <= GetLength());
EmphasisMarkDrawParams params;
params.context = aContext;
params.mark = aMark;
params.advance = aMarkAdvance;
params.direction = GetDirection();
params.isVertical = IsVertical();
gfxFloat& inlineCoord = params.isVertical ? aPt.y : aPt.x;
gfxFloat direction = params.direction;
- GlyphRunIterator iter(this, aStart, aLength);
+ GlyphRunIterator iter(this, aRange);
while (iter.NextRun()) {
gfxFont* font = iter.GetGlyphRun()->mFont;
uint32_t start = iter.GetStringStart();
uint32_t end = iter.GetStringEnd();
- uint32_t ligatureRunStart = start;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
-
- inlineCoord += direction *
- ComputePartialLigatureWidth(start, ligatureRunStart, aProvider);
+ Range ligatureRange(start, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
+
+ inlineCoord += direction * ComputePartialLigatureWidth(
+ Range(start, ligatureRange.start), aProvider);
AutoTArray<PropertyProvider::Spacing, 200> spacingBuffer;
bool haveSpacing = GetAdjustedSpacingArray(
- ligatureRunStart, ligatureRunEnd, aProvider,
- ligatureRunStart, ligatureRunEnd, &spacingBuffer);
+ ligatureRange, aProvider, ligatureRange, &spacingBuffer);
params.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr;
- font->DrawEmphasisMarks(this, &aPt, ligatureRunStart,
- ligatureRunEnd - ligatureRunStart, params);
-
- inlineCoord += direction *
- ComputePartialLigatureWidth(ligatureRunEnd, end, aProvider);
+ font->DrawEmphasisMarks(this, &aPt, ligatureRange.start,
+ ligatureRange.Length(), params);
+
+ inlineCoord += direction * ComputePartialLigatureWidth(
+ Range(ligatureRange.end, end), aProvider);
}
}
void
-gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont,
- uint32_t aStart, uint32_t aEnd,
+gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+ Range aSpacingRange,
uint16_t aOrientation,
Metrics *aMetrics)
{
AutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
- bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
- aSpacingStart, aSpacingEnd, &spacingBuffer);
- Metrics metrics = aFont->Measure(this, aStart, aEnd, aBoundingBoxType,
- aRefDrawTarget,
+ bool haveSpacing = GetAdjustedSpacingArray(aRange, aProvider,
+ aSpacingRange, &spacingBuffer);
+ Metrics metrics = aFont->Measure(this, aRange.start, aRange.end,
+ aBoundingBoxType, aRefDrawTarget,
haveSpacing ? spacingBuffer.Elements() : nullptr,
aOrientation);
aMetrics->CombineWith(metrics, IsRightToLeft());
}
void
-gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont,
- uint32_t aStart, uint32_t aEnd,
+gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider, uint16_t aOrientation, Metrics *aMetrics)
{
- if (aStart >= aEnd)
+ if (aRange.start >= aRange.end)
return;
// Measure partial ligature. We hack this by clipping the metrics in the
// same way we clip the drawing.
- LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider);
+ LigatureData data = ComputeLigatureData(aRange, aProvider);
// First measure the complete ligature
Metrics metrics;
- AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd,
+ AccumulateMetricsForRun(aFont, data.mRange,
aBoundingBoxType, aRefDrawTarget,
- aProvider, aStart, aEnd, aOrientation, &metrics);
+ aProvider, aRange, aOrientation, &metrics);
// Clip the bounding box to the ligature part
gfxFloat bboxLeft = metrics.mBoundingBox.X();
gfxFloat bboxRight = metrics.mBoundingBox.XMost();
// Where we are going to start "drawing" relative to our left baseline origin
gfxFloat origin = IsRightToLeft() ? metrics.mAdvanceWidth - data.mPartAdvance : 0;
ClipPartialLigature(this, &bboxLeft, &bboxRight, origin, &data);
metrics.mBoundingBox.x = bboxLeft;
@@ -778,48 +777,49 @@ gfxTextRun::AccumulatePartialLigatureMet
IsRightToLeft() ? metrics.mAdvanceWidth - (data.mPartAdvance + data.mPartWidth)
: data.mPartAdvance;
metrics.mAdvanceWidth = data.mPartWidth;
aMetrics->CombineWith(metrics, IsRightToLeft());
}
gfxTextRun::Metrics
-gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength,
+gfxTextRun::MeasureText(Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
+ NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range");
Metrics accumulatedMetrics;
- GlyphRunIterator iter(this, aStart, aLength);
+ GlyphRunIterator iter(this, aRange);
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
uint32_t start = iter.GetStringStart();
uint32_t end = iter.GetStringEnd();
- uint32_t ligatureRunStart = start;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
-
- AccumulatePartialLigatureMetrics(font, start, ligatureRunStart,
+ Range ligatureRange(start, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
+
+ AccumulatePartialLigatureMetrics(
+ font, Range(start, ligatureRange.start),
aBoundingBoxType, aRefDrawTarget, aProvider,
iter.GetGlyphRun()->mOrientation, &accumulatedMetrics);
// XXX This sucks. We have to get glyph extents just so we can detect
// glyphs outside the font box, even when aBoundingBoxType is LOOSE,
// even though in almost all cases we could get correct results just
// by getting some ascent/descent from the font and using our stored
// advance widths.
AccumulateMetricsForRun(font,
- ligatureRunStart, ligatureRunEnd, aBoundingBoxType,
- aRefDrawTarget, aProvider, ligatureRunStart, ligatureRunEnd,
+ ligatureRange, aBoundingBoxType,
+ aRefDrawTarget, aProvider, ligatureRange,
iter.GetGlyphRun()->mOrientation, &accumulatedMetrics);
- AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end,
+ AccumulatePartialLigatureMetrics(
+ font, Range(ligatureRange.end, end),
aBoundingBoxType, aRefDrawTarget, aProvider,
iter.GetGlyphRun()->mOrientation, &accumulatedMetrics);
}
return accumulatedMetrics;
}
#define MEASUREMENT_BUFFER_SIZE 100
@@ -837,76 +837,72 @@ gfxTextRun::BreakAndMeasureText(uint32_t
uint32_t *aLastBreak,
bool aCanWordWrap,
gfxBreakPriority *aBreakPriority)
{
aMaxLength = std::min(aMaxLength, GetLength() - aStart);
NS_ASSERTION(aStart + aMaxLength <= GetLength(), "Substring out of range");
- uint32_t bufferStart = aStart;
- uint32_t bufferLength = std::min<uint32_t>(aMaxLength, MEASUREMENT_BUFFER_SIZE);
+ Range bufferRange(aStart, aStart +
+ std::min<uint32_t>(aMaxLength, MEASUREMENT_BUFFER_SIZE));
PropertyProvider::Spacing spacingBuffer[MEASUREMENT_BUFFER_SIZE];
bool haveSpacing = aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING) != 0;
if (haveSpacing) {
- GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
- spacingBuffer);
+ GetAdjustedSpacing(this, bufferRange, aProvider, spacingBuffer);
}
bool hyphenBuffer[MEASUREMENT_BUFFER_SIZE];
bool haveHyphenation = aProvider &&
(aProvider->GetHyphensOption() == NS_STYLE_HYPHENS_AUTO ||
(aProvider->GetHyphensOption() == NS_STYLE_HYPHENS_MANUAL &&
(mFlags & gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS) != 0));
if (haveHyphenation) {
- aProvider->GetHyphenationBreaks(bufferStart, bufferLength,
- hyphenBuffer);
+ aProvider->GetHyphenationBreaks(bufferRange, hyphenBuffer);
}
gfxFloat width = 0;
gfxFloat advance = 0;
// The number of space characters that can be trimmed
uint32_t trimmableChars = 0;
// The amount of space removed by ignoring trimmableChars
gfxFloat trimmableAdvance = 0;
int32_t lastBreak = -1;
int32_t lastBreakTrimmableChars = -1;
gfxFloat lastBreakTrimmableAdvance = -1;
bool aborted = false;
uint32_t end = aStart + aMaxLength;
bool lastBreakUsedHyphenation = false;
- uint32_t ligatureRunStart = aStart;
- uint32_t ligatureRunEnd = end;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
+ Range ligatureRange(aStart, end);
+ ShrinkToLigatureBoundaries(&ligatureRange);
uint32_t i;
for (i = aStart; i < end; ++i) {
- if (i >= bufferStart + bufferLength) {
+ if (i >= bufferRange.end) {
// Fetch more spacing and hyphenation data
- bufferStart = i;
- bufferLength = std::min(aStart + aMaxLength, i + MEASUREMENT_BUFFER_SIZE) - i;
+ bufferRange.start = i;
+ bufferRange.end = std::min(aStart + aMaxLength,
+ i + MEASUREMENT_BUFFER_SIZE);
if (haveSpacing) {
- GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider,
- spacingBuffer);
+ GetAdjustedSpacing(this, bufferRange, aProvider, spacingBuffer);
}
if (haveHyphenation) {
- aProvider->GetHyphenationBreaks(bufferStart, bufferLength,
- hyphenBuffer);
+ aProvider->GetHyphenationBreaks(bufferRange, hyphenBuffer);
}
}
// There can't be a word-wrap break opportunity at the beginning of the
// line: if the width is too small for even one character to fit, it
// could be the first and last break opportunity on the line, and that
// would trigger an infinite loop.
if (aSuppressBreak != eSuppressAllBreaks &&
(aSuppressBreak != eSuppressInitialBreak || i > aStart)) {
bool atNaturalBreak = mCharacterGlyphs[i].CanBreakBefore() == 1;
- bool atHyphenationBreak =
- !atNaturalBreak && haveHyphenation && hyphenBuffer[i - bufferStart];
+ bool atHyphenationBreak = !atNaturalBreak &&
+ haveHyphenation && hyphenBuffer[i - bufferRange.start];
bool atBreak = atNaturalBreak || atHyphenationBreak;
bool wordWrapping =
aCanWordWrap && mCharacterGlyphs[i].IsClusterStart() &&
*aBreakPriority <= gfxBreakPriority::eWordWrapBreak;
if (atBreak || wordWrapping) {
gfxFloat hyphenatedAdvance = advance;
if (atHyphenationBreak) {
@@ -929,24 +925,26 @@ gfxTextRun::BreakAndMeasureText(uint32_t
// No more text fits. Abort
aborted = true;
break;
}
}
}
gfxFloat charAdvance;
- if (i >= ligatureRunStart && i < ligatureRunEnd) {
- charAdvance = GetAdvanceForGlyphs(i, i + 1);
+ if (i >= ligatureRange.start && i < ligatureRange.end) {
+ charAdvance = GetAdvanceForGlyphs(Range(i, i + 1));
if (haveSpacing) {
- PropertyProvider::Spacing *space = &spacingBuffer[i - bufferStart];
+ PropertyProvider::Spacing *space =
+ &spacingBuffer[i - bufferRange.start];
charAdvance += space->mBefore + space->mAfter;
}
} else {
- charAdvance = ComputePartialLigatureWidth(i, i + 1, aProvider);
+ charAdvance =
+ ComputePartialLigatureWidth(Range(i, i + 1), aProvider);
}
advance += charAdvance;
if (aTrimWhitespace) {
if (mCharacterGlyphs[i].CharIsSpace()) {
++trimmableChars;
trimmableAdvance += charAdvance;
} else {
@@ -973,23 +971,23 @@ gfxTextRun::BreakAndMeasureText(uint32_t
trimmableChars = lastBreakTrimmableChars;
trimmableAdvance = lastBreakTrimmableAdvance;
usedHyphenation = lastBreakUsedHyphenation;
} else {
charsFit = aMaxLength;
}
if (aMetrics) {
- *aMetrics = MeasureText(aStart, charsFit, aBoundingBoxType,
+ auto end = aStart + charsFit;
+ *aMetrics = MeasureText(Range(aStart, end), aBoundingBoxType,
aRefDrawTarget, aProvider);
if (trimmableChars) {
Metrics trimMetrics =
- MeasureText(aStart + charsFit - trimmableChars,
- trimmableChars, aBoundingBoxType,
- aRefDrawTarget, aProvider);
+ MeasureText(Range(end - trimmableChars, end),
+ aBoundingBoxType, aRefDrawTarget, aProvider);
aMetrics->mAdvanceWidth -= trimMetrics.mAdvanceWidth;
}
}
if (aTrimWhitespace) {
*aTrimWhitespace = trimmableAdvance;
}
if (aUsedHyphenation) {
*aUsedHyphenation = usedHyphenation;
@@ -1001,57 +999,58 @@ gfxTextRun::BreakAndMeasureText(uint32_t
*aLastBreak = lastBreak - aStart;
}
}
return charsFit;
}
gfxFloat
-gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
- PropertyProvider *aProvider,
+gfxTextRun::GetAdvanceWidth(Range aRange, PropertyProvider *aProvider,
PropertyProvider::Spacing* aSpacing)
{
- NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range");
-
- uint32_t ligatureRunStart = aStart;
- uint32_t ligatureRunEnd = aStart + aLength;
- ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd);
-
- gfxFloat result = ComputePartialLigatureWidth(aStart, ligatureRunStart, aProvider) +
- ComputePartialLigatureWidth(ligatureRunEnd, aStart + aLength, aProvider);
+ NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range");
+
+ Range ligatureRange = aRange;
+ ShrinkToLigatureBoundaries(&ligatureRange);
+
+ gfxFloat result =
+ ComputePartialLigatureWidth(Range(aRange.start, ligatureRange.start),
+ aProvider) +
+ ComputePartialLigatureWidth(Range(ligatureRange.end, aRange.end),
+ aProvider);
if (aSpacing) {
aSpacing->mBefore = aSpacing->mAfter = 0;
}
// Account for all remaining spacing here. This is more efficient than
// processing it along with the glyphs.
if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) {
uint32_t i;
AutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
- if (spacingBuffer.AppendElements(aLength)) {
- GetAdjustedSpacing(this, ligatureRunStart, ligatureRunEnd, aProvider,
+ if (spacingBuffer.AppendElements(aRange.Length())) {
+ GetAdjustedSpacing(this, ligatureRange, aProvider,
spacingBuffer.Elements());
- for (i = 0; i < ligatureRunEnd - ligatureRunStart; ++i) {
+ for (i = 0; i < ligatureRange.Length(); ++i) {
PropertyProvider::Spacing *space = &spacingBuffer[i];
result += space->mBefore + space->mAfter;
}
if (aSpacing) {
aSpacing->mBefore = spacingBuffer[0].mBefore;
aSpacing->mAfter = spacingBuffer.LastElement().mAfter;
}
}
}
- return result + GetAdvanceForGlyphs(ligatureRunStart, ligatureRunEnd);
+ return result + GetAdvanceForGlyphs(ligatureRange);
}
bool
-gfxTextRun::SetLineBreaks(uint32_t aStart, uint32_t aLength,
+gfxTextRun::SetLineBreaks(Range aRange,
bool aLineBreakBefore, bool aLineBreakAfter,
gfxFloat *aAdvanceWidthDelta)
{
// Do nothing because our shaping does not currently take linebreaks into
// account. There is no change in advance width.
if (aAdvanceWidthDelta) {
*aAdvanceWidthDelta = 0;
}
@@ -1239,57 +1238,57 @@ gfxTextRun::CopyGlyphDataFrom(gfxShapedW
}
} else {
memcpy(charGlyphs + aOffset, wordGlyphs,
wordLen * sizeof(CompressedGlyph));
}
}
void
-gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
- uint32_t aLength, uint32_t aDest)
+gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, Range aRange, uint32_t aDest)
{
- NS_ASSERTION(aStart + aLength <= aSource->GetLength(),
+ NS_ASSERTION(aRange.end <= aSource->GetLength(),
"Source substring out of range");
- NS_ASSERTION(aDest + aLength <= GetLength(),
+ NS_ASSERTION(aDest + aRange.Length() <= GetLength(),
"Destination substring out of range");
if (aSource->mSkipDrawing) {
mSkipDrawing = true;
}
// Copy base glyph data, and DetailedGlyph data where present
- const CompressedGlyph *srcGlyphs = aSource->mCharacterGlyphs + aStart;
+ const CompressedGlyph *srcGlyphs = aSource->mCharacterGlyphs + aRange.start;
CompressedGlyph *dstGlyphs = mCharacterGlyphs + aDest;
- for (uint32_t i = 0; i < aLength; ++i) {
+ for (uint32_t i = 0; i < aRange.Length(); ++i) {
CompressedGlyph g = srcGlyphs[i];
g.SetCanBreakBefore(!g.IsClusterStart() ?
CompressedGlyph::FLAG_BREAK_TYPE_NONE :
dstGlyphs[i].CanBreakBefore());
if (!g.IsSimpleGlyph()) {
uint32_t count = g.GetGlyphCount();
if (count > 0) {
DetailedGlyph *dst = AllocateDetailedGlyphs(i + aDest, count);
if (dst) {
- DetailedGlyph *src = aSource->GetDetailedGlyphs(i + aStart);
+ DetailedGlyph *src =
+ aSource->GetDetailedGlyphs(i + aRange.start);
if (src) {
::memcpy(dst, src, count * sizeof(DetailedGlyph));
} else {
g.SetMissing(0);
}
} else {
g.SetMissing(0);
}
}
}
dstGlyphs[i] = g;
}
// Copy glyph runs
- GlyphRunIterator iter(aSource, aStart, aLength);
+ GlyphRunIterator iter(aSource, aRange);
#ifdef DEBUG
GlyphRun *prevRun = nullptr;
#endif
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
NS_ASSERTION(!prevRun || prevRun->mFont != iter.GetGlyphRun()->mFont ||
prevRun->mMatchType != iter.GetGlyphRun()->mMatchType ||
prevRun->mOrientation != iter.GetGlyphRun()->mOrientation,
@@ -1310,17 +1309,17 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun
// but it's the best we can do for now if the specified font only covered the
// initial base character and not its applied marks.
NS_WARN_IF_FALSE(aSource->IsClusterStart(start),
"Started font run in the middle of a cluster");
NS_WARN_IF_FALSE(end == aSource->GetLength() || aSource->IsClusterStart(end),
"Ended font run in the middle of a cluster");
nsresult rv = AddGlyphRun(font, iter.GetGlyphRun()->mMatchType,
- start - aStart + aDest, false,
+ start - aRange.start + aDest, false,
iter.GetGlyphRun()->mOrientation);
if (NS_FAILED(rv))
return;
}
}
void
gfxTextRun::ClearGlyphsAndCharacters()
@@ -1490,42 +1489,42 @@ gfxTextRun::ClusterIterator::NextCluster
return true;
}
}
mCurrentChar = uint32_t(-1);
return false;
}
-uint32_t
-gfxTextRun::ClusterIterator::ClusterLength() const
+gfxTextRun::Range
+gfxTextRun::ClusterIterator::ClusterRange() const
{
if (mCurrentChar == uint32_t(-1)) {
- return 0;
+ return Range(0, 0);
}
uint32_t i = mCurrentChar,
len = mTextRun->GetLength();
while (++i < len) {
if (mTextRun->IsClusterStart(i)) {
break;
}
}
- return i - mCurrentChar;
+ return Range(mCurrentChar, i);
}
gfxFloat
gfxTextRun::ClusterIterator::ClusterAdvance(PropertyProvider *aProvider) const
{
if (mCurrentChar == uint32_t(-1)) {
return 0;
}
- return mTextRun->GetAdvanceWidth(mCurrentChar, ClusterLength(), aProvider);
+ return mTextRun->GetAdvanceWidth(ClusterRange(), aProvider);
}
size_t
gfxTextRun::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)
{
// The second arg is how much gfxTextRun::AllocateStorage would have
// allocated.
size_t total = mGlyphRuns.ShallowSizeOfExcludingThis(aMallocSizeOf);
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -129,53 +129,64 @@ public:
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
return mCharacterGlyphs[aPos].CharIsNewline();
}
bool CharMayHaveEmphasisMark(uint32_t aPos) const {
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark();
}
- // All uint32_t aStart, uint32_t aLength ranges below are restricted to
- // grapheme cluster boundaries! All offsets are in terms of the string
- // passed into MakeTextRun.
-
+ // All offsets are in terms of the string passed into MakeTextRun.
+
+ // Describe range [start, end) of a text run. The range is
+ // restricted to grapheme cluster boundaries.
+ struct Range
+ {
+ uint32_t start;
+ uint32_t end;
+ uint32_t Length() const { return end - start; }
+
+ Range() : start(0), end(0) {}
+ Range(uint32_t aStart, uint32_t aEnd)
+ : start(aStart), end(aEnd) {}
+ explicit Range(gfxTextRun* aTextRun)
+ : start(0), end(aTextRun->GetLength()) {}
+ };
+
// All coordinates are in layout/app units
/**
* Set the potential linebreaks for a substring of the textrun. These are
* the "allow break before" points. Initially, there are no potential
* linebreaks.
*
* This can change glyphs and/or geometry! Some textruns' shapes
* depend on potential line breaks (e.g., title-case-converting textruns).
* This function is virtual so that those textruns can reshape themselves.
*
* @return true if this changed the linebreaks, false if the new line
* breaks are the same as the old
*/
- virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
- uint8_t *aBreakBefore);
+ virtual bool SetPotentialLineBreaks(Range aRange, uint8_t *aBreakBefore);
/**
* Layout provides PropertyProvider objects. These allow detection of
* potential line break points and computation of spacing. We pass the data
* this way to allow lazy data acquisition; for example BreakAndMeasureText
* will want to only ask for properties of text it's actually looking at.
*
* NOTE that requested spacing may not actually be applied, if the textrun
* is unable to apply it in some context. Exception: spacing around a
* whitespace character MUST always be applied.
*/
class PropertyProvider {
public:
// Detect hyphenation break opportunities in the given range; breaks
// not at cluster boundaries will be ignored.
- virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
- bool *aBreakBefore) = 0;
+ virtual void GetHyphenationBreaks(Range aRange, bool *aBreakBefore) = 0;
// Returns the provider's hyphenation setting, so callers can decide
// whether it is necessary to call GetHyphenationBreaks.
// Result is an NS_STYLE_HYPHENS_* value.
virtual int8_t GetHyphensOption() = 0;
// Returns the extra width that will be consumed by a hyphen. This should
// be constant for a given textrun.
@@ -184,18 +195,17 @@ public:
typedef gfxFont::Spacing Spacing;
/**
* Get the spacing around the indicated characters. Spacing must be zero
* inside clusters. In other words, if character i is not
* CLUSTER_START, then character i-1 must have zero after-spacing and
* character i must have zero before-spacing.
*/
- virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
- Spacing *aSpacing) = 0;
+ virtual void GetSpacing(Range aRange, Spacing *aSpacing) = 0;
// Returns a gfxContext that can be used to measure the hyphen glyph.
// Only called if the hyphen width is requested.
virtual already_AddRefed<DrawTarget> GetDrawTarget() = 0;
// Return the appUnitsPerDevUnit value to be used when measuring.
// Only called if the hyphen width is requested.
virtual uint32_t GetAppUnitsPerDevUnit() = 0;
@@ -208,98 +218,95 @@ public:
void Reset();
bool NextCluster();
uint32_t Position() const {
return mCurrentChar;
}
- uint32_t ClusterLength() const;
+ Range ClusterRange() const;
gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
private:
gfxTextRun *mTextRun;
uint32_t mCurrentChar;
};
/**
* Draws a substring. Uses only GetSpacing from aBreakProvider.
* The provided point is the baseline origin on the left of the string
* for LTR, on the right of the string for RTL.
* @param aAdvanceWidth if non-null, the advance width of the substring
* is returned here.
*
* Drawing should respect advance widths in the sense that for LTR runs,
- * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
- * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
+ * Draw(ctx, pt, Range(start, middle), dirty, &provider, &advance) followed by
+ * Draw(ctx, gfxPoint(pt.x + advance, pt.y), Range(middle, end),
* dirty, &provider, nullptr) should have the same effect as
- * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
+ * Draw(ctx, pt, Range(start, end), dirty, &provider, nullptr).
* For RTL runs the rule is:
- * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
- * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
+ * Draw(ctx, pt, Range(middle, end), dirty, &provider, &advance) followed by
+ * Draw(ctx, gfxPoint(pt.x + advance, pt.y), Range(start, middle),
* dirty, &provider, nullptr) should have the same effect as
- * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
+ * Draw(ctx, pt, Range(start, end), dirty, &provider, nullptr).
*
* Glyphs should be drawn in logical content order, which can be significant
* if they overlap (perhaps due to negative spacing).
*/
void Draw(gfxContext *aContext, gfxPoint aPt,
- DrawMode aDrawMode,
- uint32_t aStart, uint32_t aLength,
+ DrawMode aDrawMode, Range aRange,
PropertyProvider *aProvider,
gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint,
gfxTextRunDrawCallbacks *aCallbacks = nullptr);
/**
* Draws the emphasis marks for this text run. Uses only GetSpacing
* from aProvider. The provided point is the baseline origin of the
* line of emphasis marks.
*/
void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
gfxFloat aMarkAdvance, gfxPoint aPt,
- uint32_t aStart, uint32_t aLength,
- PropertyProvider* aProvider);
+ Range aRange, PropertyProvider* aProvider);
/**
* Computes the ReflowMetrics for a substring.
* Uses GetSpacing from aBreakProvider.
* @param aBoundingBoxType which kind of bounding box (loose/tight)
*/
- Metrics MeasureText(uint32_t aStart, uint32_t aLength,
+ Metrics MeasureText(Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aDrawTargetForTightBoundingBox,
PropertyProvider* aProvider);
Metrics MeasureText(gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aDrawTargetForTightBoundingBox,
PropertyProvider* aProvider = nullptr) {
- return MeasureText(0, GetLength(), aBoundingBoxType,
+ return MeasureText(Range(this), aBoundingBoxType,
aDrawTargetForTightBoundingBox, aProvider);
}
/**
* Computes just the advance width for a substring.
* Uses GetSpacing from aBreakProvider.
* If aSpacing is not null, the spacing attached before and after
* the substring would be returned in it. NOTE: the spacing is
* included in the advance width.
*/
- gfxFloat GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
- PropertyProvider *aProvider,
+ gfxFloat GetAdvanceWidth(Range aRange, PropertyProvider *aProvider,
PropertyProvider::Spacing* aSpacing = nullptr);
gfxFloat GetAdvanceWidth() {
- return GetAdvanceWidth(0, GetLength(), nullptr);
+ return GetAdvanceWidth(Range(this), nullptr);
}
/**
* Clear all stored line breaks for the given range (both before and after),
- * and then set the line-break state before aStart to aBreakBefore and
+ * and then set the line-break state before aRange.start to aBreakBefore and
* after the last cluster to aBreakAfter.
*
* We require that before and after line breaks be consistent. For clusters
* i and i+1, we require that if there is a break after cluster i, a break
* will be specified before cluster i+1. This may be temporarily violated
* (e.g. after reflowing line L and before reflowing line L+1); to handle
* these temporary violations, we say that there is a break betwen i and i+1
* if a break is specified after i OR a break is specified before i+1.
@@ -314,19 +321,19 @@ public:
*
* We return true if glyphs or geometry changed, false otherwise. This
* function is virtual so that gfxTextRun subclasses can reshape
* properly.
*
* @param aAdvanceWidthDelta if non-null, returns the change in advance
* width of the given range.
*/
- virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength,
- bool aLineBreakBefore, bool aLineBreakAfter,
- gfxFloat* aAdvanceWidthDelta);
+ virtual bool SetLineBreaks(Range aRange,
+ bool aLineBreakBefore, bool aLineBreakAfter,
+ gfxFloat* aAdvanceWidthDelta);
enum SuppressBreak {
eNoSuppressBreak,
// Measure the range of text as if there is no break before it.
eSuppressInitialBreak,
// Measure the range of text as if it contains no break
eSuppressAllBreaks
};
@@ -429,19 +436,21 @@ public:
RefPtr<gfxFont> mFont; // never null
uint32_t mCharacterOffset; // into original UTF16 string
uint8_t mMatchType;
uint16_t mOrientation; // gfxTextRunFactory::TEXT_ORIENT_* value
};
class GlyphRunIterator {
public:
- GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength)
- : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
- mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
+ GlyphRunIterator(gfxTextRun *aTextRun, Range aRange)
+ : mTextRun(aTextRun)
+ , mStartOffset(aRange.start)
+ , mEndOffset(aRange.end) {
+ mNextIndex = mTextRun->FindFirstGlyphRunContaining(aRange.start);
}
bool NextRun();
GlyphRun *GetGlyphRun() { return mGlyphRun; }
uint32_t GetStringStart() { return mStringStart; }
uint32_t GetStringEnd() { return mStringEnd; }
private:
gfxTextRun *mTextRun;
GlyphRun *mGlyphRun;
@@ -552,33 +561,31 @@ public:
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
uint32_t FindFirstGlyphRunContaining(uint32_t aOffset);
// Copy glyph data from a ShapedWord into this textrun.
void CopyGlyphDataFrom(gfxShapedWord *aSource, uint32_t aStart);
// Copy glyph data for a range of characters from aSource to this
// textrun.
- void CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
- uint32_t aLength, uint32_t aDest);
+ void CopyGlyphDataFrom(gfxTextRun *aSource, Range aRange, uint32_t aDest);
nsExpirationState *GetExpirationState() { return &mExpirationState; }
// Tell the textrun to release its reference to its creating gfxFontGroup
// immediately, rather than on destruction. This is used for textruns
// that are actually owned by a gfxFontGroup, so that they don't keep it
// permanently alive due to a circular reference. (The caller of this is
// taking responsibility for ensuring the textrun will not outlive its
// mFontGroup.)
void ReleaseFontGroup();
struct LigatureData {
- // textrun offsets of the start and end of the containing ligature
- uint32_t mLigatureStart;
- uint32_t mLigatureEnd;
+ // textrun range of the containing ligature
+ Range mRange;
// appunits advance to the start of the ligature part within the ligature;
// never includes any spacing
gfxFloat mPartAdvance;
// appunits width of the ligature part; includes before-spacing
// when the part is at the start of the ligature, and after-spacing
// when the part is as the end of the ligature
gfxFloat mPartWidth;
@@ -664,71 +671,69 @@ protected:
// Pointer to the array of CompressedGlyph records; must be initialized
// when the object is constructed.
CompressedGlyph *mCharacterGlyphs;
private:
// **** general helpers ****
// Get the total advance for a range of glyphs.
- int32_t GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd);
+ int32_t GetAdvanceForGlyphs(Range aRange);
// Spacing for characters outside the range aSpacingStart/aSpacingEnd
// is assumed to be zero; such characters are not passed to aProvider.
// This is useful to protect aProvider from being passed character indices
// it is not currently able to handle.
- bool GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd,
- PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
- nsTArray<PropertyProvider::Spacing> *aSpacing);
+ bool GetAdjustedSpacingArray(Range aRange, PropertyProvider *aProvider,
+ Range aSpacingRange,
+ nsTArray<PropertyProvider::Spacing> *aSpacing);
CompressedGlyph& EnsureComplexGlyph(uint32_t aIndex)
{
gfxShapedText::EnsureComplexGlyph(aIndex, mCharacterGlyphs[aIndex]);
return mCharacterGlyphs[aIndex];
}
// **** ligature helpers ****
// (Platforms do the actual ligaturization, but we need to do a bunch of stuff
// to handle requests that begin or end inside a ligature)
// if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
- LigatureData ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
+ LigatureData ComputeLigatureData(Range aPartRange,
PropertyProvider *aProvider);
- gfxFloat ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd,
+ gfxFloat ComputePartialLigatureWidth(Range aPartRange,
PropertyProvider *aProvider);
- void DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
+ void DrawPartialLigature(gfxFont *aFont, Range aRange,
gfxPoint *aPt, PropertyProvider *aProvider,
TextRunDrawParams& aParams, uint16_t aOrientation);
- // Advance aStart to the start of the nearest ligature; back up aEnd
- // to the nearest ligature end; may result in *aStart == *aEnd
- void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd);
+ // Advance aRange.start to the start of the nearest ligature, back
+ // up aRange.end to the nearest ligature end; may result in
+ // aRange->start == aRange->end.
+ void ShrinkToLigatureBoundaries(Range* aRange);
// result in appunits
- gfxFloat GetPartialLigatureWidth(uint32_t aStart, uint32_t aEnd, PropertyProvider *aProvider);
- void AccumulatePartialLigatureMetrics(gfxFont *aFont,
- uint32_t aStart, uint32_t aEnd,
+ gfxFloat GetPartialLigatureWidth(Range aRange, PropertyProvider *aProvider);
+ void AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider,
uint16_t aOrientation,
Metrics *aMetrics);
// **** measurement helper ****
- void AccumulateMetricsForRun(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
+ void AccumulateMetricsForRun(gfxFont *aFont, Range aRange,
gfxFont::BoundingBoxType aBoundingBoxType,
DrawTarget* aRefDrawTarget,
PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+ Range aSpacingRange,
uint16_t aOrientation,
Metrics *aMetrics);
// **** drawing helper ****
- void DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
- gfxPoint *aPt, PropertyProvider *aProvider,
- uint32_t aSpacingStart, uint32_t aSpacingEnd,
+ void DrawGlyphs(gfxFont *aFont, Range aRange, gfxPoint *aPt,
+ PropertyProvider *aProvider, Range aSpacingRange,
TextRunDrawParams& aParams, uint16_t aOrientation);
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
// for smaller size especially in the super-common one-glyphrun case
AutoTArray<GlyphRun,1> mGlyphRuns;
void *mUserData;
gfxFontGroup *mFontGroup; // addrefed on creation, but our reference
--- a/layout/generic/MathMLTextRunFactory.cpp
+++ b/layout/generic/MathMLTextRunFactory.cpp
@@ -768,22 +768,25 @@ MathMLTextRunFactory::RebuildTextRun(nsT
} else {
cachedChild = newFontGroup->MakeTextRun(
convertedString.BeginReading(), convertedString.Length(),
&innerParams, flags, aMFR);
child = cachedChild.get();
}
if (!child)
return;
+
+ typedef gfxTextRun::Range Range;
+
// Copy potential linebreaks into child so they're preserved
// (and also child will be shaped appropriately)
NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(),
"Dropped characters or break-before values somewhere!");
- child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
- canBreakBeforeArray.Elements());
+ Range range(0, uint32_t(canBreakBeforeArray.Length()));
+ child->SetPotentialLineBreaks(range, canBreakBeforeArray.Elements());
if (transformedChild) {
transformedChild->FinishSettingProperties(aRefDrawTarget, aMFR);
}
if (mergeNeeded) {
// Now merge multiple characters into one multi-glyph character as required
NS_ASSERTION(charsToMergeArray.Length() == child->GetLength(),
"source length mismatch");
@@ -791,11 +794,11 @@ MathMLTextRunFactory::RebuildTextRun(nsT
"destination length mismatch");
MergeCharactersInTextRun(aTextRun, child, charsToMergeArray.Elements(),
deletedCharsArray.Elements());
} else {
// No merging to do, so just copy; this produces a more optimized textrun.
// We can't steal the data because the child may be cached and stealing
// the data would break the cache.
aTextRun->ResetGlyphRuns();
- aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0);
+ aTextRun->CopyGlyphDataFrom(child, Range(child), 0);
}
}
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -248,17 +248,17 @@ nsDisplayTextOverflowMarker::PaintTextTo
if (mStyle->mType == NS_STYLE_TEXT_OVERFLOW_ELLIPSIS) {
gfxTextRun* textRun = GetEllipsisTextRun(mFrame);
if (textRun) {
NS_ASSERTION(!textRun->IsRightToLeft(),
"Ellipsis textruns should always be LTR!");
gfxPoint gfxPt(pt.x, pt.y);
textRun->Draw(aCtx->ThebesContext(), gfxPt, DrawMode::GLYPH_FILL,
- 0, textRun->GetLength(), nullptr, nullptr, nullptr);
+ gfxTextRun::Range(textRun), nullptr, nullptr, nullptr);
}
} else {
RefPtr<nsFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(mFrame, getter_AddRefs(fm),
nsLayoutUtils::FontSizeInflationFor(mFrame));
nsLayoutUtils::DrawString(mFrame, *fm, aCtx, mStyle->mString.get(),
mStyle->mString.Length(), pt);
}
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -974,18 +974,19 @@ public:
uint32_t aOffsetIntoTextRun)
: mTextRun(aTextRun)
, mDrawTarget(aDrawTarget)
, mOffsetIntoTextRun(aOffsetIntoTextRun)
{}
virtual void SetBreaks(uint32_t aOffset, uint32_t aLength,
uint8_t* aBreakBefore) override {
- if (mTextRun->SetPotentialLineBreaks(aOffset + mOffsetIntoTextRun, aLength,
- aBreakBefore)) {
+ gfxTextRun::Range range(aOffset + mOffsetIntoTextRun,
+ aOffset + mOffsetIntoTextRun + aLength);
+ if (mTextRun->SetPotentialLineBreaks(range, aBreakBefore)) {
// Be conservative and assume that some breaks have been set
mTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_NO_BREAKS);
}
}
virtual void SetCapitalization(uint32_t aOffset, uint32_t aLength,
bool* aCapitalize) override {
MOZ_ASSERT(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED,
@@ -2922,28 +2923,30 @@ static bool IsChineseOrJapanese(nsTextFr
return false;
}
return nsStyleUtil::MatchesLanguagePrefix(language, MOZ_UTF16("ja")) ||
nsStyleUtil::MatchesLanguagePrefix(language, MOZ_UTF16("zh"));
}
#ifdef DEBUG
static bool IsInBounds(const gfxSkipCharsIterator& aStart, int32_t aContentLength,
- uint32_t aOffset, uint32_t aLength) {
- if (aStart.GetSkippedOffset() > aOffset)
+ gfxTextRun::Range aRange) {
+ if (aStart.GetSkippedOffset() > aRange.start)
return false;
if (aContentLength == INT32_MAX)
return true;
gfxSkipCharsIterator iter(aStart);
iter.AdvanceOriginal(aContentLength);
- return iter.GetSkippedOffset() >= aOffset + aLength;
+ return iter.GetSkippedOffset() >= aRange.end;
}
#endif
class MOZ_STACK_CLASS PropertyProvider : public gfxTextRun::PropertyProvider {
+ typedef gfxTextRun::Range Range;
+
public:
/**
* Use this constructor for reflow, when we don't know what text is
* really mapped by the frame and we have a lot of other data around.
*
* @param aLength can be INT32_MAX to indicate we cover all the text
* associated with aFrame up to where its flow chain ends in the given
* textrun. If INT32_MAX is passed, justification and hyphen-related methods
@@ -2997,40 +3000,38 @@ public:
NS_ASSERTION(mTextRun, "Textrun not initialized!");
}
// Call this after construction if you're not going to reflow the text
void InitializeForDisplay(bool aTrimAfter);
void InitializeForMeasure();
- virtual void GetSpacing(uint32_t aStart, uint32_t aLength, Spacing* aSpacing);
+ virtual void GetSpacing(Range aRange, Spacing* aSpacing);
virtual gfxFloat GetHyphenWidth();
- virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
- bool* aBreakBefore);
+ virtual void GetHyphenationBreaks(Range aRange, bool* aBreakBefore);
virtual int8_t GetHyphensOption() {
return mTextStyle->mHyphens;
}
virtual already_AddRefed<DrawTarget> GetDrawTarget() {
return CreateReferenceDrawTarget(GetFrame());
}
virtual uint32_t GetAppUnitsPerDevUnit() {
return mTextRun->GetAppUnitsPerDevUnit();
}
- void GetSpacingInternal(uint32_t aStart, uint32_t aLength, Spacing* aSpacing,
- bool aIgnoreTabs);
+ void GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs);
/**
* Compute the justification information in given DOM range, and fill data
* necessary for computation of spacing.
*/
- void ComputeJustification(int32_t aOffset, int32_t aLength);
+ void ComputeJustification(Range aRange);
const nsStyleText* StyleText() { return mTextStyle; }
nsTextFrame* GetFrame() { return mFrame; }
// This may not be equal to the frame offset/length in because we may have
// adjusted for whitespace trimming according to the state bits set in the frame
// (for the static provider)
const gfxSkipCharsIterator& GetStart() { return mStart; }
// May return INT32_MAX if that was given to the constructor
@@ -3047,17 +3048,17 @@ public:
}
nsFontMetrics* GetFontMetrics() {
if (!mFontMetrics)
InitFontGroupAndFontMetrics();
return mFontMetrics;
}
- void CalcTabWidths(uint32_t aTransformedStart, uint32_t aTransformedLength);
+ void CalcTabWidths(Range aTransformedRange);
const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; }
const JustificationInfo& GetJustificationInfo() const
{
return mJustificationInfo;
}
@@ -3142,26 +3143,26 @@ static void FindClusterEnd(gfxTextRun* a
break;
}
aPos->AdvanceOriginal(1);
}
aPos->AdvanceOriginal(-1);
}
void
-PropertyProvider::ComputeJustification(int32_t aOffset, int32_t aLength)
+PropertyProvider::ComputeJustification(Range aRange)
{
bool isCJ = IsChineseOrJapanese(mFrame);
- nsSkipCharsRunIterator
- run(mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aLength);
- run.SetOriginalOffset(aOffset);
+ nsSkipCharsRunIterator run(
+ mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aRange.Length());
+ run.SetOriginalOffset(aRange.start);
mJustificationArrayStart = run.GetSkippedOffset();
MOZ_ASSERT(mJustificationAssignments.IsEmpty());
- mJustificationAssignments.SetCapacity(aLength);
+ mJustificationAssignments.SetCapacity(aRange.Length());
while (run.NextRun()) {
uint32_t originalOffset = run.GetOriginalOffset();
uint32_t skippedOffset = run.GetSkippedOffset();
uint32_t length = run.GetRunLength();
mJustificationAssignments.SetLength(
skippedOffset + length - mJustificationArrayStart);
gfxSkipCharsIterator iter = run.GetPos();
@@ -3210,103 +3211,105 @@ PropertyProvider::ComputeJustification(i
MOZ_ASSERT(mJustificationInfo.mInnerOpportunities > 0);
mJustificationInfo.mInnerOpportunities--;
mJustificationInfo.mIsEndJustifiable = true;
}
}
// aStart, aLength in transformed string offsets
void
-PropertyProvider::GetSpacing(uint32_t aStart, uint32_t aLength,
- Spacing* aSpacing)
-{
- GetSpacingInternal(aStart, aLength, aSpacing,
+PropertyProvider::GetSpacing(Range aRange, Spacing* aSpacing)
+{
+ GetSpacingInternal(aRange, aSpacing,
(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TAB) == 0);
}
static bool
CanAddSpacingAfter(gfxTextRun* aTextRun, uint32_t aOffset)
{
if (aOffset + 1 >= aTextRun->GetLength())
return true;
return aTextRun->IsClusterStart(aOffset + 1) &&
aTextRun->IsLigatureGroupStart(aOffset + 1);
}
void
-PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength,
- Spacing* aSpacing, bool aIgnoreTabs)
-{
- NS_PRECONDITION(IsInBounds(mStart, mLength, aStart, aLength), "Range out of bounds");
+PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing,
+ bool aIgnoreTabs)
+{
+ NS_PRECONDITION(IsInBounds(mStart, mLength, aRange), "Range out of bounds");
uint32_t index;
- for (index = 0; index < aLength; ++index) {
+ for (index = 0; index < aRange.Length(); ++index) {
aSpacing[index].mBefore = 0.0;
aSpacing[index].mAfter = 0.0;
}
// Find our offset into the original+transformed string
gfxSkipCharsIterator start(mStart);
- start.SetSkippedOffset(aStart);
+ start.SetSkippedOffset(aRange.start);
// First, compute the word and letter spacing
if (mWordSpacing || mLetterSpacing) {
// Iterate over non-skipped characters
- nsSkipCharsRunIterator
- run(start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength);
+ nsSkipCharsRunIterator run(
+ start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length());
while (run.NextRun()) {
- uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aStart;
+ uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start;
gfxSkipCharsIterator iter = run.GetPos();
for (int32_t i = 0; i < run.GetRunLength(); ++i) {
if (CanAddSpacingAfter(mTextRun, run.GetSkippedOffset() + i)) {
// End of a cluster, not in a ligature: put letter-spacing after it
aSpacing[runOffsetInSubstring + i].mAfter += mLetterSpacing;
}
if (IsCSSWordSpacingSpace(mFrag, i + run.GetOriginalOffset(),
mFrame, mTextStyle)) {
// It kinda sucks, but space characters can be part of clusters,
// and even still be whitespace (I think!)
iter.SetSkippedOffset(run.GetSkippedOffset() + i);
FindClusterEnd(mTextRun, run.GetOriginalOffset() + run.GetRunLength(),
&iter);
- aSpacing[iter.GetSkippedOffset() - aStart].mAfter += mWordSpacing;
+ uint32_t runOffset = iter.GetSkippedOffset() - aRange.start;
+ aSpacing[runOffset].mAfter += mWordSpacing;
}
}
}
}
// Ignore tab spacing rather than computing it, if the tab size is 0
if (!aIgnoreTabs)
aIgnoreTabs = mFrame->StyleText()->mTabSize == 0;
// Now add tab spacing, if there is any
if (!aIgnoreTabs) {
- CalcTabWidths(aStart, aLength);
+ CalcTabWidths(aRange);
if (mTabWidths) {
mTabWidths->ApplySpacing(aSpacing,
- aStart - mStart.GetSkippedOffset(), aLength);
+ aRange.start - mStart.GetSkippedOffset(),
+ aRange.Length());
}
}
// Now add in justification spacing
if (mJustificationSpacing > 0 && mTotalJustificationGaps) {
// If there is any spaces trimmed at the end, aStart + aLength may
// be larger than the flags array. When that happens, we can simply
// ignore those spaces.
auto arrayEnd = mJustificationArrayStart +
static_cast<uint32_t>(mJustificationAssignments.Length());
- auto end = std::min(aStart + aLength, arrayEnd);
- MOZ_ASSERT(aStart >= mJustificationArrayStart);
+ auto end = std::min(aRange.end, arrayEnd);
+ MOZ_ASSERT(aRange.start >= mJustificationArrayStart);
JustificationApplicationState state(
mTotalJustificationGaps, NSToCoordRound(mJustificationSpacing));
- for (auto i = aStart; i < end; i++) {
+ for (auto i = aRange.start; i < end; i++) {
const auto& assign =
mJustificationAssignments[i - mJustificationArrayStart];
- aSpacing[i - aStart].mBefore += state.Consume(assign.mGapsAtStart);
- aSpacing[i - aStart].mAfter += state.Consume(assign.mGapsAtEnd);
+ uint32_t offset = i - aRange.start;
+ aSpacing[offset].mBefore += state.Consume(assign.mGapsAtStart);
+ aSpacing[offset].mAfter += state.Consume(assign.mGapsAtEnd);
}
}
}
static gfxFloat
ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
{
// Get the number of spaces from CSS -moz-tab-size
@@ -3326,68 +3329,68 @@ AdvanceToNextTab(gfxFloat aX, nsIFrame*
// Advance aX to the next multiple of *aCachedTabWidth. We must advance
// by at least 1 appunit.
// XXX should we make this 1 CSS pixel?
return ceil((aX + 1)/(*aCachedTabWidth))*(*aCachedTabWidth);
}
void
-PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength)
+PropertyProvider::CalcTabWidths(Range aRange)
{
if (!mTabWidths) {
if (mReflowing && !mLineContainer) {
// Intrinsic width computation does its own tab processing. We
// just don't do anything here.
return;
}
if (!mReflowing) {
mTabWidths = static_cast<TabWidthStore*>
(mFrame->Properties().Get(TabWidthProperty()));
#ifdef DEBUG
// If we're not reflowing, we should have already computed the
// tab widths; check that they're available as far as the last
// tab character present (if any)
- for (uint32_t i = aStart + aLength; i > aStart; --i) {
+ for (uint32_t i = aRange.end; i > aRange.start; --i) {
if (mTextRun->CharIsTab(i - 1)) {
uint32_t startOffset = mStart.GetSkippedOffset();
NS_ASSERTION(mTabWidths && mTabWidths->mLimit + startOffset >= i,
"Precomputed tab widths are missing!");
break;
}
}
#endif
return;
}
}
uint32_t startOffset = mStart.GetSkippedOffset();
- MOZ_ASSERT(aStart >= startOffset, "wrong start offset");
- MOZ_ASSERT(aStart + aLength <= startOffset + mLength, "beyond the end");
+ MOZ_ASSERT(aRange.start >= startOffset, "wrong start offset");
+ MOZ_ASSERT(aRange.end <= startOffset + mLength, "beyond the end");
uint32_t tabsEnd =
(mTabWidths ? mTabWidths->mLimit : mTabWidthsAnalyzedLimit) + startOffset;
- if (tabsEnd < aStart + aLength) {
+ if (tabsEnd < aRange.end) {
NS_ASSERTION(mReflowing,
"We need precomputed tab widths, but don't have enough.");
gfxFloat tabWidth = -1;
- for (uint32_t i = tabsEnd; i < aStart + aLength; ++i) {
+ for (uint32_t i = tabsEnd; i < aRange.end; ++i) {
Spacing spacing;
- GetSpacingInternal(i, 1, &spacing, true);
+ GetSpacingInternal(Range(i, i + 1), &spacing, true);
mOffsetFromBlockOriginForTabs += spacing.mBefore;
if (!mTextRun->CharIsTab(i)) {
if (mTextRun->IsClusterStart(i)) {
uint32_t clusterEnd = i + 1;
while (clusterEnd < mTextRun->GetLength() &&
!mTextRun->IsClusterStart(clusterEnd)) {
++clusterEnd;
}
mOffsetFromBlockOriginForTabs +=
- mTextRun->GetAdvanceWidth(i, clusterEnd - i, nullptr);
+ mTextRun->GetAdvanceWidth(Range(i, clusterEnd), nullptr);
}
} else {
if (!mTabWidths) {
mTabWidths = new TabWidthStore(mFrame->GetContentOffset());
mFrame->Properties().Set(TabWidthProperty(), mTabWidths);
}
double nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs,
mFrame, mTextRun, &tabWidth);
@@ -3395,55 +3398,54 @@ PropertyProvider::CalcTabWidths(uint32_t
NSToIntRound(nextTab - mOffsetFromBlockOriginForTabs)));
mOffsetFromBlockOriginForTabs = nextTab;
}
mOffsetFromBlockOriginForTabs += spacing.mAfter;
}
if (mTabWidths) {
- mTabWidths->mLimit = aStart + aLength - startOffset;
+ mTabWidths->mLimit = aRange.end - startOffset;
}
}
if (!mTabWidths) {
// Delete any stale property that may be left on the frame
mFrame->Properties().Delete(TabWidthProperty());
mTabWidthsAnalyzedLimit = std::max(mTabWidthsAnalyzedLimit,
- aStart + aLength - startOffset);
+ aRange.end - startOffset);
}
}
gfxFloat
PropertyProvider::GetHyphenWidth()
{
if (mHyphenWidth < 0) {
mHyphenWidth = GetFontGroup()->GetHyphenWidth(this);
}
return mHyphenWidth + mLetterSpacing;
}
void
-PropertyProvider::GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
- bool* aBreakBefore)
-{
- NS_PRECONDITION(IsInBounds(mStart, mLength, aStart, aLength), "Range out of bounds");
+PropertyProvider::GetHyphenationBreaks(Range aRange, bool* aBreakBefore)
+{
+ NS_PRECONDITION(IsInBounds(mStart, mLength, aRange), "Range out of bounds");
NS_PRECONDITION(mLength != INT32_MAX, "Can't call this with undefined length");
if (!mTextStyle->WhiteSpaceCanWrap(mFrame) ||
mTextStyle->mHyphens == NS_STYLE_HYPHENS_NONE)
{
- memset(aBreakBefore, false, aLength*sizeof(bool));
+ memset(aBreakBefore, false, aRange.Length() * sizeof(bool));
return;
}
// Iterate through the original-string character runs
- nsSkipCharsRunIterator
- run(mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength);
- run.SetSkippedOffset(aStart);
+ nsSkipCharsRunIterator run(
+ mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length());
+ run.SetSkippedOffset(aRange.start);
// We need to visit skipped characters so that we can detect SHY
run.SetVisitSkipped();
int32_t prevTrailingCharOffset = run.GetPos().GetOriginalOffset() - 1;
bool allowHyphenBreakBeforeNextChar =
prevTrailingCharOffset >= mStart.GetOriginalOffset() &&
prevTrailingCharOffset < mStart.GetOriginalOffset() + mLength &&
mFrag->CharAt(prevTrailingCharOffset) == CH_SHY;
@@ -3452,29 +3454,29 @@ PropertyProvider::GetHyphenationBreaks(u
NS_ASSERTION(run.GetRunLength() > 0, "Shouldn't return zero-length runs");
if (run.IsSkipped()) {
// Check if there's a soft hyphen which would let us hyphenate before
// the next non-skipped character. Don't look at soft hyphens followed
// by other skipped characters, we won't use them.
allowHyphenBreakBeforeNextChar =
mFrag->CharAt(run.GetOriginalOffset() + run.GetRunLength() - 1) == CH_SHY;
} else {
- int32_t runOffsetInSubstring = run.GetSkippedOffset() - aStart;
+ int32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start;
memset(aBreakBefore + runOffsetInSubstring, false, run.GetRunLength()*sizeof(bool));
// Don't allow hyphen breaks at the start of the line
aBreakBefore[runOffsetInSubstring] = allowHyphenBreakBeforeNextChar &&
(!(mFrame->GetStateBits() & TEXT_START_OF_LINE) ||
run.GetSkippedOffset() > mStart.GetSkippedOffset());
allowHyphenBreakBeforeNextChar = false;
}
}
if (mTextStyle->mHyphens == NS_STYLE_HYPHENS_AUTO) {
- for (uint32_t i = 0; i < aLength; ++i) {
- if (mTextRun->CanHyphenateBefore(aStart + i)) {
+ for (uint32_t i = 0; i < aRange.Length(); ++i) {
+ if (mTextRun->CanHyphenateBefore(aRange.start + i)) {
aBreakBefore[i] = true;
}
}
}
}
void
PropertyProvider::InitializeForDisplay(bool aTrimAfter)
@@ -3492,56 +3494,50 @@ PropertyProvider::InitializeForMeasure()
nsTextFrame::TrimmedOffsets trimmed =
mFrame->GetTrimmedOffsets(mFrag, true, false);
mStart.SetOriginalOffset(trimmed.mStart);
mLength = trimmed.mLength;
SetupJustificationSpacing(false);
}
-static uint32_t GetSkippedDistance(const gfxSkipCharsIterator& aStart,
- const gfxSkipCharsIterator& aEnd)
-{
- return aEnd.GetSkippedOffset() - aStart.GetSkippedOffset();
-}
-
void
PropertyProvider::SetupJustificationSpacing(bool aPostReflow)
{
NS_PRECONDITION(mLength != INT32_MAX, "Can't call this with undefined length");
if (!(mFrame->GetStateBits() & TEXT_JUSTIFICATION_ENABLED))
return;
gfxSkipCharsIterator start(mStart), end(mStart);
// We can't just use our mLength here; when InitializeForDisplay is
// called with false for aTrimAfter, we still shouldn't be assigning
// justification space to any trailing whitespace.
nsTextFrame::TrimmedOffsets trimmed =
mFrame->GetTrimmedOffsets(mFrag, true, aPostReflow);
end.AdvanceOriginal(trimmed.mLength);
gfxSkipCharsIterator realEnd(end);
- ComputeJustification(start.GetOriginalOffset(),
- end.GetOriginalOffset() - start.GetOriginalOffset());
+ ComputeJustification(Range(uint32_t(start.GetOriginalOffset()),
+ uint32_t(end.GetOriginalOffset())));
auto assign = mFrame->GetJustificationAssignment();
mTotalJustificationGaps =
JustificationUtils::CountGaps(mJustificationInfo, assign);
if (!mTotalJustificationGaps || mJustificationAssignments.IsEmpty()) {
// Nothing to do, nothing is justifiable and we shouldn't have any
// justification space assigned
return;
}
// Remember that textrun measurements are in the run's orientation,
// so its advance "width" is actually a height in vertical writing modes,
// corresponding to the inline-direction of the frame.
gfxFloat naturalWidth =
- mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(),
- GetSkippedDistance(mStart, realEnd), this);
+ mTextRun->GetAdvanceWidth(Range(mStart.GetSkippedOffset(),
+ realEnd.GetSkippedOffset()), this);
if (mFrame->GetStateBits() & TEXT_HYPHEN_BREAK) {
naturalWidth += GetHyphenWidth();
}
mJustificationSpacing = mFrame->ISize() - naturalWidth;
if (mJustificationSpacing <= 0) {
// No space available
return;
}
@@ -5735,99 +5731,99 @@ public:
/**
* aStart and aLength are in the original string. aSelectionDetails is
* according to the original string.
* @param aXOffset the offset from the origin of the frame to the start
* of the text (the left baseline origin for LTR, the right baseline origin
* for RTL)
*/
SelectionIterator(SelectionDetails** aSelectionDetails,
- int32_t aStart, int32_t aLength,
- PropertyProvider& aProvider, gfxTextRun* aTextRun,
- gfxFloat aXOffset);
+ gfxTextRun::Range aRange, PropertyProvider& aProvider,
+ gfxTextRun* aTextRun, gfxFloat aXOffset);
/**
* Returns the next segment of uniformly selected (or not) text.
* @param aXOffset the offset from the origin of the frame to the start
* of the text (the left baseline origin for LTR, the right baseline origin
* for RTL)
- * @param aOffset the transformed string offset of the text for this segment
- * @param aLength the transformed string length of the text for this segment
+ * @param aRange the transformed string range of the text for this segment
* @param aHyphenWidth if a hyphen is to be rendered after the text, the
* width of the hyphen, otherwise zero
* @param aType the selection type for this segment
* @param aStyle the selection style for this segment
* @return false if there are no more segments
*/
- bool GetNextSegment(gfxFloat* aXOffset, uint32_t* aOffset, uint32_t* aLength,
- gfxFloat* aHyphenWidth, SelectionType* aType,
- TextRangeStyle* aStyle);
+ bool GetNextSegment(gfxFloat* aXOffset, gfxTextRun::Range* aRange,
+ gfxFloat* aHyphenWidth, SelectionType* aType,
+ TextRangeStyle* aStyle);
void UpdateWithAdvance(gfxFloat aAdvance) {
mXOffset += aAdvance*mTextRun->GetDirection();
}
private:
SelectionDetails** mSelectionDetails;
PropertyProvider& mProvider;
gfxTextRun* mTextRun;
gfxSkipCharsIterator mIterator;
- int32_t mOriginalStart;
- int32_t mOriginalEnd;
+ gfxTextRun::Range mOriginalRange;
gfxFloat mXOffset;
};
SelectionIterator::SelectionIterator(SelectionDetails** aSelectionDetails,
- int32_t aStart, int32_t aLength, PropertyProvider& aProvider,
- gfxTextRun* aTextRun, gfxFloat aXOffset)
+ gfxTextRun::Range aRange,
+ PropertyProvider& aProvider,
+ gfxTextRun* aTextRun, gfxFloat aXOffset)
: mSelectionDetails(aSelectionDetails), mProvider(aProvider),
mTextRun(aTextRun), mIterator(aProvider.GetStart()),
- mOriginalStart(aStart), mOriginalEnd(aStart + aLength),
- mXOffset(aXOffset)
-{
- mIterator.SetOriginalOffset(aStart);
+ mOriginalRange(aRange), mXOffset(aXOffset)
+{
+ mIterator.SetOriginalOffset(aRange.start);
}
bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
- uint32_t* aOffset, uint32_t* aLength, gfxFloat* aHyphenWidth,
- SelectionType* aType, TextRangeStyle* aStyle)
-{
- if (mIterator.GetOriginalOffset() >= mOriginalEnd)
+ gfxTextRun::Range* aRange,
+ gfxFloat* aHyphenWidth,
+ SelectionType* aType,
+ TextRangeStyle* aStyle)
+{
+ if (mIterator.GetOriginalOffset() >= int32_t(mOriginalRange.end))
return false;
// save offset into transformed string now
uint32_t runOffset = mIterator.GetSkippedOffset();
- int32_t index = mIterator.GetOriginalOffset() - mOriginalStart;
+ uint32_t index = mIterator.GetOriginalOffset() - mOriginalRange.start;
SelectionDetails* sdptr = mSelectionDetails[index];
SelectionType type =
sdptr ? sdptr->mType : nsISelectionController::SELECTION_NONE;
TextRangeStyle style;
if (sdptr) {
style = sdptr->mTextRangeStyle;
}
- for (++index; mOriginalStart + index < mOriginalEnd; ++index) {
+ for (++index; index < mOriginalRange.Length(); ++index) {
if (sdptr != mSelectionDetails[index])
break;
}
- mIterator.SetOriginalOffset(index + mOriginalStart);
+ mIterator.SetOriginalOffset(index + mOriginalRange.start);
// Advance to the next cluster boundary
- while (mIterator.GetOriginalOffset() < mOriginalEnd &&
+ while (mIterator.GetOriginalOffset() < int32_t(mOriginalRange.end) &&
!mIterator.IsOriginalCharSkipped() &&
!mTextRun->IsClusterStart(mIterator.GetSkippedOffset())) {
mIterator.AdvanceOriginal(1);
}
bool haveHyphenBreak =
(mProvider.GetFrame()->GetStateBits() & TEXT_HYPHEN_BREAK) != 0;
- *aOffset = runOffset;
- *aLength = mIterator.GetSkippedOffset() - runOffset;
+ aRange->start = runOffset;
+ aRange->end = mIterator.GetSkippedOffset();
*aXOffset = mXOffset;
*aHyphenWidth = 0;
- if (mIterator.GetOriginalOffset() == mOriginalEnd && haveHyphenBreak) {
+ if (mIterator.GetOriginalOffset() == int32_t(mOriginalRange.end) &&
+ haveHyphenBreak) {
*aHyphenWidth = mProvider.GetHyphenWidth();
}
*aType = type;
*aStyle = style;
return true;
}
static void
@@ -5846,17 +5842,17 @@ AddHyphenToMetrics(nsTextFrame* aTextFra
hyphenTextRun->MeasureText(aBoundingBoxType, aDrawTarget);
if (aTextFrame->GetWritingMode().IsLineInverted()) {
hyphenMetrics.mBoundingBox.y = -hyphenMetrics.mBoundingBox.YMost();
}
aMetrics->CombineWith(hyphenMetrics, aBaseTextRun->IsRightToLeft());
}
void
-nsTextFrame::PaintOneShadow(uint32_t aOffset, uint32_t aLength,
+nsTextFrame::PaintOneShadow(Range aRange,
nsCSSShadowItem* aShadowDetails,
PropertyProvider* aProvider, const nsRect& aDirtyRect,
const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
gfxContext* aCtx, const nscolor& aForegroundColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
nscoord aLeftSideOffset, gfxRect& aBoundingBox,
uint32_t aBlurFlags)
{
@@ -5917,58 +5913,58 @@ nsTextFrame::PaintOneShadow(uint32_t aOf
// Draw the text onto our alpha-only surface to capture the alpha values.
// Remember that the box blur context has a device offset on it, so we don't need to
// translate any coordinates to fit on the surface.
gfxFloat advanceWidth;
gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height);
DrawText(shadowContext, dirtyRect, aFramePt + shadowOffset,
- aTextBaselinePt + shadowOffset, aOffset, aLength, *aProvider,
+ aTextBaselinePt + shadowOffset, aRange, *aProvider,
nsTextPaintStyle(this),
aCtx == shadowContext ? shadowColor : NS_RGB(0, 0, 0), aClipEdges,
advanceWidth, (GetStateBits() & TEXT_HYPHEN_BREAK) != 0,
decorationOverrideColor);
contextBoxBlur.DoPaint();
aCtx->Restore();
}
// Paints selection backgrounds and text in the correct colors. Also computes
// aAllTypes, the union of all selection types that are applying to this text.
bool
nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset, uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
SelectionType* aAllTypes,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
// Figure out which selections control the colors to use for each character.
AutoTArray<SelectionDetails*,BIG_TEXT_NODE_SIZE> prevailingSelectionsBuffer;
SelectionDetails** prevailingSelections =
- prevailingSelectionsBuffer.AppendElements(aContentLength, fallible);
+ prevailingSelectionsBuffer.AppendElements(aContentRange.Length(), fallible);
if (!prevailingSelections) {
return false;
}
SelectionType allTypes = 0;
- for (uint32_t i = 0; i < aContentLength; ++i) {
+ for (uint32_t i = 0; i < aContentRange.Length(); ++i) {
prevailingSelections[i] = nullptr;
}
SelectionDetails *sdptr = aDetails;
bool anyBackgrounds = false;
while (sdptr) {
- int32_t start = std::max(0, sdptr->mStart - int32_t(aContentOffset));
- int32_t end = std::min(int32_t(aContentLength),
- sdptr->mEnd - int32_t(aContentOffset));
+ int32_t start = std::max(0, sdptr->mStart - int32_t(aContentRange.start));
+ int32_t end = std::min(int32_t(aContentRange.Length()),
+ sdptr->mEnd - int32_t(aContentRange.start));
SelectionType type = sdptr->mType;
if (start < end) {
allTypes |= type;
// Ignore selections that don't set colors
nscolor foreground, background;
if (GetSelectionTextColors(type, aTextPaintStyle, sdptr->mTextRangeStyle,
&foreground, &background)) {
if (NS_GET_A(background) > 0) {
@@ -5991,33 +5987,33 @@ nsTextFrame::PaintTextWithSelectionColor
// Nothing is selected in the given text range. XXX can this still occur?
return false;
}
bool vertical = mTextRun->IsVertical();
const gfxFloat startIOffset = vertical ?
aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
gfxFloat iOffset, hyphenWidth;
- uint32_t offset, length; // in transformed string
+ Range range; // in transformed string
SelectionType type;
TextRangeStyle rangeStyle;
// Draw background colors
if (anyBackgrounds) {
int32_t appUnitsPerDevPixel = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect dirtyRect = AppUnitGfxRectToDevRect(aDirtyRect, appUnitsPerDevPixel);
- SelectionIterator iterator(prevailingSelections, aContentOffset, aContentLength,
+ SelectionIterator iterator(prevailingSelections, aContentRange,
aProvider, mTextRun, startIOffset);
- while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
+ while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&type, &rangeStyle)) {
nscolor foreground, background;
GetSelectionTextColors(type, aTextPaintStyle, rangeStyle,
&foreground, &background);
// Draw background color
gfxFloat advance = hyphenWidth +
- mTextRun->GetAdvanceWidth(offset, length, &aProvider);
+ mTextRun->GetAdvanceWidth(range, &aProvider);
if (NS_GET_A(background) > 0) {
gfxRect bgRect;
gfxFloat offs = iOffset - (mTextRun->IsInlineReversed() ? advance : 0);
if (vertical) {
bgRect = gfxRect(aFramePt.x, aFramePt.y + offs,
GetSize().width, advance);
} else {
bgRect = gfxRect(aFramePt.x + offs, aFramePt.y,
@@ -6030,83 +6026,82 @@ nsTextFrame::PaintTextWithSelectionColor
iterator.UpdateWithAdvance(advance);
}
}
// Draw text
const nsStyleText* textStyle = StyleText();
nsRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height);
- SelectionIterator iterator(prevailingSelections, aContentOffset, aContentLength,
+ SelectionIterator iterator(prevailingSelections, aContentRange,
aProvider, mTextRun, startIOffset);
- while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
+ while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&type, &rangeStyle)) {
nscolor foreground, background;
GetSelectionTextColors(type, aTextPaintStyle, rangeStyle,
&foreground, &background);
gfxPoint textBaselinePt = vertical ?
gfxPoint(aTextBaselinePt.x, aFramePt.y + iOffset) :
gfxPoint(aFramePt.x + iOffset, aTextBaselinePt.y);
// Determine what shadow, if any, to draw - either from textStyle
// or from the ::-moz-selection pseudo-class if specified there
nsCSSShadowArray* shadow = textStyle->GetTextShadow();
GetSelectionTextShadow(this, type, aTextPaintStyle, &shadow);
if (shadow) {
nscoord startEdge = iOffset;
if (mTextRun->IsInlineReversed()) {
- startEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
- hyphenWidth;
- }
- PaintShadows(shadow, offset, length, dirtyRect, aFramePt, textBaselinePt,
+ startEdge -= hyphenWidth +
+ mTextRun->GetAdvanceWidth(range, &aProvider);
+ }
+ PaintShadows(shadow, range, dirtyRect, aFramePt, textBaselinePt,
startEdge, aProvider, foreground, aClipEdges, aCtx);
}
// Draw text segment
gfxFloat advance;
DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
- offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges,
+ range, aProvider, aTextPaintStyle, foreground, aClipEdges,
advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks);
advance += hyphenWidth;
iterator.UpdateWithAdvance(advance);
}
return true;
}
void
nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect,
- PropertyProvider& aProvider,
- uint32_t aContentOffset, uint32_t aContentLength,
+ PropertyProvider& aProvider, Range aContentRange,
nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails,
SelectionType aSelectionType,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
// Hide text decorations if we're currently hiding @font-face fallback text
if (aProvider.GetFontGroup()->ShouldSkipDrawing())
return;
// Figure out which characters will be decorated for this selection.
AutoTArray<SelectionDetails*, BIG_TEXT_NODE_SIZE> selectedCharsBuffer;
SelectionDetails** selectedChars =
- selectedCharsBuffer.AppendElements(aContentLength, fallible);
+ selectedCharsBuffer.AppendElements(aContentRange.Length(), fallible);
if (!selectedChars) {
return;
}
- for (uint32_t i = 0; i < aContentLength; ++i) {
+ for (uint32_t i = 0; i < aContentRange.Length(); ++i) {
selectedChars[i] = nullptr;
}
SelectionDetails *sdptr = aDetails;
while (sdptr) {
if (sdptr->mType == aSelectionType) {
- int32_t start = std::max(0, sdptr->mStart - int32_t(aContentOffset));
- int32_t end = std::min(int32_t(aContentLength),
- sdptr->mEnd - int32_t(aContentOffset));
+ int32_t start = std::max(0, sdptr->mStart - int32_t(aContentRange.start));
+ int32_t end = std::min(int32_t(aContentRange.Length()),
+ sdptr->mEnd - int32_t(aContentRange.start));
for (int32_t i = start; i < end; ++i) {
selectedChars[i] = sdptr;
}
}
sdptr = sdptr->mNext;
}
gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont();
@@ -6123,37 +6118,37 @@ nsTextFrame::PaintTextSelectionDecoratio
// The potential adjustment from using gfxFontGroup::GetUnderlineOffset
// is only valid for horizontal font metrics.
decorationMetrics.underlineOffset =
aProvider.GetFontGroup()->GetUnderlineOffset();
}
gfxFloat startIOffset =
verticalRun ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
- SelectionIterator iterator(selectedChars, aContentOffset, aContentLength,
+ SelectionIterator iterator(selectedChars, aContentRange,
aProvider, mTextRun, startIOffset);
gfxFloat iOffset, hyphenWidth;
- uint32_t offset, length;
+ Range range;
int32_t app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
// XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint?
Point pt;
if (verticalRun) {
pt.x = (aTextBaselinePt.x - mAscent) / app;
} else {
pt.y = (aTextBaselinePt.y - mAscent) / app;
}
gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app,
aDirtyRect.width / app, aDirtyRect.height / app);
gfxFloat decorationOffsetDir = mTextRun->IsSidewaysLeft() ? -1.0 : 1.0;
SelectionType type;
TextRangeStyle selectedStyle;
- while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
+ while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&type, &selectedStyle)) {
gfxFloat advance = hyphenWidth +
- mTextRun->GetAdvanceWidth(offset, length, &aProvider);
+ mTextRun->GetAdvanceWidth(range, &aProvider);
if (type == aSelectionType) {
if (verticalRun) {
pt.y = (aFramePt.y + iOffset -
(mTextRun->IsInlineReversed() ? advance : 0)) / app;
} else {
pt.x = (aFramePt.x + iOffset -
(mTextRun->IsInlineReversed() ? advance : 0)) / app;
}
@@ -6169,32 +6164,32 @@ nsTextFrame::PaintTextSelectionDecoratio
}
}
bool
nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset, uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxTextContextPaint* aContextPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
NS_ASSERTION(GetContent()->IsSelectionDescendant(), "wrong paint path");
SelectionDetails* details = GetSelectionDetails();
if (!details) {
return false;
}
SelectionType allTypes;
if (!PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
- aProvider, aContentOffset, aContentLength,
+ aProvider, aContentRange,
aTextPaintStyle, details, &allTypes,
aClipEdges, aCallbacks)) {
DestroySelectionDetails(details);
return false;
}
// Iterate through just the selection types that paint decorations and
// paint decorations for any that actually occur in this frame. Paint
// higher-numbered selection types below lower-numered ones on the
@@ -6203,30 +6198,29 @@ nsTextFrame::PaintTextWithSelection(gfxC
for (int32_t i = nsISelectionController::NUM_SELECTIONTYPES - 1;
i >= 1; --i) {
SelectionType type = 1 << (i - 1);
if (allTypes & type) {
// There is some selection of this type. Try to paint its decorations
// (there might not be any for this type but that's OK,
// PaintTextSelectionDecorations will exit early).
PaintTextSelectionDecorations(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
- aProvider, aContentOffset, aContentLength,
- aTextPaintStyle, details, type,
- aCallbacks);
+ aProvider, aContentRange, aTextPaintStyle,
+ details, type, aCallbacks);
}
}
DestroySelectionDetails(details);
return true;
}
void
nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nscolor* aDecorationOverrideColor,
PropertyProvider& aProvider)
{
const auto info = Properties().Get(EmphasisMarkProperty());
if (!info) {
return;
}
@@ -6239,17 +6233,17 @@ nsTextFrame::DrawEmphasisMarks(gfxContex
} else {
if (aWM.IsVerticalRL()) {
pt.x -= info->baselineOffset;
} else {
pt.x += info->baselineOffset;
}
}
mTextRun->DrawEmphasisMarks(aContext, info->textRun, info->advance,
- pt, aOffset, aLength, &aProvider);
+ pt, aRange, &aProvider);
}
nscolor
nsTextFrame::GetCaretColorAt(int32_t aOffset)
{
NS_PRECONDITION(aOffset >= 0, "aOffset must be positive");
nscolor result = nsFrame::GetCaretColorAt(aOffset);
@@ -6299,23 +6293,23 @@ nsTextFrame::GetCaretColorAt(int32_t aOf
}
sdptr = sdptr->mNext;
}
DestroySelectionDetails(details);
return result;
}
-static uint32_t
-ComputeTransformedLength(PropertyProvider& aProvider)
+static gfxTextRun::Range
+ComputeTransformedRange(PropertyProvider& aProvider)
{
gfxSkipCharsIterator iter(aProvider.GetStart());
uint32_t start = iter.GetSkippedOffset();
iter.AdvanceOriginal(aProvider.GetOriginalLength());
- return iter.GetSkippedOffset() - start;
+ return gfxTextRun::Range(start, iter.GetSkippedOffset());
}
bool
nsTextFrame::MeasureCharClippedText(nscoord aVisIStartEdge,
nscoord aVisIEndEdge,
nscoord* aSnappedStartEdge,
nscoord* aSnappedEndEdge)
{
@@ -6325,18 +6319,19 @@ nsTextFrame::MeasureCharClippedText(nsco
gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated);
if (!mTextRun)
return false;
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
// Trim trailing whitespace
provider.InitializeForDisplay(true);
- uint32_t startOffset = provider.GetStart().GetSkippedOffset();
- uint32_t maxLength = ComputeTransformedLength(provider);
+ Range range = ComputeTransformedRange(provider);
+ uint32_t startOffset = range.start;
+ uint32_t maxLength = range.Length();
return MeasureCharClippedText(provider, aVisIStartEdge, aVisIEndEdge,
&startOffset, &maxLength,
aSnappedStartEdge, aSnappedEndEdge);
}
static uint32_t GetClusterLength(gfxTextRun* aTextRun,
uint32_t aStartOffset,
uint32_t aMaxLength,
@@ -6376,18 +6371,18 @@ nsTextFrame::MeasureCharClippedText(Prop
const bool rtl = mTextRun->IsRightToLeft();
gfxFloat advanceWidth = 0;
const nscoord startEdge = rtl ? aVisIEndEdge : aVisIStartEdge;
if (startEdge > 0) {
const gfxFloat maxAdvance = gfxFloat(startEdge);
while (maxLength > 0) {
uint32_t clusterLength =
GetClusterLength(mTextRun, offset, maxLength, rtl);
- advanceWidth +=
- mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider);
+ advanceWidth += mTextRun->
+ GetAdvanceWidth(Range(offset, offset + clusterLength), &aProvider);
maxLength -= clusterLength;
offset += clusterLength;
if (advanceWidth >= maxAdvance) {
break;
}
}
nscoord* snappedStartEdge = rtl ? aSnappedEndEdge : aSnappedStartEdge;
*snappedStartEdge = NSToCoordFloor(advanceWidth);
@@ -6395,18 +6390,18 @@ nsTextFrame::MeasureCharClippedText(Prop
}
const nscoord endEdge = rtl ? aVisIStartEdge : aVisIEndEdge;
if (endEdge > 0) {
const gfxFloat maxAdvance = gfxFloat(frameISize - endEdge);
while (maxLength > 0) {
uint32_t clusterLength =
GetClusterLength(mTextRun, offset, maxLength, rtl);
- gfxFloat nextAdvance = advanceWidth +
- mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider);
+ gfxFloat nextAdvance = advanceWidth + mTextRun->GetAdvanceWidth(
+ Range(offset, offset + clusterLength), &aProvider);
if (nextAdvance > maxAdvance) {
break;
}
// This cluster fits, include it.
advanceWidth = nextAdvance;
maxLength -= clusterLength;
offset += clusterLength;
}
@@ -6415,32 +6410,32 @@ nsTextFrame::MeasureCharClippedText(Prop
*snappedEndEdge = NSToCoordFloor(gfxFloat(frameISize) - advanceWidth);
}
*aMaxLength = maxLength;
return maxLength != 0;
}
void
nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nsRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
nscoord aLeftEdgeOffset,
PropertyProvider& aProvider,
nscolor aForegroundColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxContext* aCtx)
{
if (!aShadow) {
return;
}
gfxTextRun::Metrics shadowMetrics =
- mTextRun->MeasureText(aOffset, aLength, gfxFont::LOOSE_INK_EXTENTS,
+ mTextRun->MeasureText(aRange, gfxFont::LOOSE_INK_EXTENTS,
nullptr, &aProvider);
if (GetWritingMode().IsLineInverted()) {
Swap(shadowMetrics.mAscent, shadowMetrics.mDescent);
shadowMetrics.mBoundingBox.y = -shadowMetrics.mBoundingBox.YMost();
}
if (GetStateBits() & TEXT_HYPHEN_BREAK) {
AddHyphenToMetrics(this, mTextRun, &shadowMetrics,
gfxFont::LOOSE_INK_EXTENTS, aCtx->GetDrawTarget());
@@ -6465,18 +6460,17 @@ nsTextFrame::PaintShadows(nsCSSShadowArr
}
if (mTextRun->IsVertical()) {
Swap(shadowMetrics.mBoundingBox.x, shadowMetrics.mBoundingBox.y);
Swap(shadowMetrics.mBoundingBox.width, shadowMetrics.mBoundingBox.height);
}
for (uint32_t i = aShadow->Length(); i > 0; --i) {
- PaintOneShadow(aOffset, aLength,
- aShadow->ShadowAt(i - 1), &aProvider,
+ PaintOneShadow(aRange, aShadow->ShadowAt(i - 1), &aProvider,
aDirtyRect, aFramePt, aTextBaselinePt, aCtx,
aForegroundColor, aClipEdges,
aLeftEdgeOffset,
shadowMetrics.mBoundingBox,
blurFlags);
}
}
@@ -6520,18 +6514,19 @@ nsTextFrame::PaintText(nsRenderingContex
-mAscent);
}
textBaselinePt.y = reversed ? aPt.y + GetSize().height : aPt.y;
} else {
textBaselinePt =
gfxPoint(reversed ? gfxFloat(aPt.x + frameWidth) : framePt.x,
nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent));
}
- uint32_t startOffset = provider.GetStart().GetSkippedOffset();
- uint32_t maxLength = ComputeTransformedLength(provider);
+ Range range = ComputeTransformedRange(provider);
+ uint32_t startOffset = range.start;
+ uint32_t maxLength = range.Length();
nscoord snappedStartEdge, snappedEndEdge;
if (!MeasureCharClippedText(provider, aItem.mVisIStartEdge, aItem.mVisIEndEdge,
&startOffset, &maxLength, &snappedStartEdge, &snappedEndEdge)) {
return;
}
if (verticalRun) {
textBaselinePt.y += reversed ? -snappedEndEdge : snappedStartEdge;
} else {
@@ -6543,109 +6538,109 @@ nsTextFrame::PaintText(nsRenderingContex
textPaintStyle.SetResolveColors(!aCallbacks);
gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height);
// Fork off to the (slower) paint-with-selection path if necessary.
if (aItem.mIsFrameSelected.value()) {
MOZ_ASSERT(aOpacity == 1.0f, "We don't support opacity with selections!");
gfxSkipCharsIterator tmp(provider.GetStart());
- int32_t contentOffset = tmp.ConvertSkippedToOriginal(startOffset);
- int32_t contentLength =
- tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset;
+ Range contentRange(
+ uint32_t(tmp.ConvertSkippedToOriginal(startOffset)),
+ uint32_t(tmp.ConvertSkippedToOriginal(startOffset + maxLength)));
if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect,
- provider, contentOffset, contentLength,
- textPaintStyle, clipEdges, aContextPaint,
- aCallbacks)) {
+ provider, contentRange, textPaintStyle,
+ clipEdges, aContextPaint, aCallbacks)) {
return;
}
}
nscolor foregroundColor = textPaintStyle.GetTextColor();
if (aOpacity != 1.0f) {
gfx::Color gfxColor = gfx::Color::FromABGR(foregroundColor);
gfxColor.a *= aOpacity;
foregroundColor = gfxColor.ToABGR();
}
+ range = Range(startOffset, startOffset + maxLength);
if (!aCallbacks) {
const nsStyleText* textStyle = StyleText();
- PaintShadows(textStyle->mTextShadow, startOffset, maxLength,
- aDirtyRect, framePt, textBaselinePt, snappedStartEdge, provider,
- foregroundColor, clipEdges, ctx);
+ PaintShadows(
+ textStyle->mTextShadow, range, aDirtyRect, framePt, textBaselinePt,
+ snappedStartEdge, provider, foregroundColor, clipEdges, ctx);
}
gfxFloat advanceWidth;
- DrawText(ctx, dirtyRect, framePt, textBaselinePt, startOffset, maxLength, provider,
+ DrawText(ctx, dirtyRect, framePt, textBaselinePt, range, provider,
textPaintStyle, foregroundColor, clipEdges, advanceWidth,
(GetStateBits() & TEXT_HYPHEN_BREAK) != 0,
nullptr, aContextPaint, aCallbacks);
}
static void
DrawTextRun(gfxTextRun* aTextRun,
gfxContext* const aCtx,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ gfxTextRun::Range aRange,
PropertyProvider* aProvider,
nscolor aTextColor,
gfxFloat* aAdvanceWidth,
gfxTextContextPaint* aContextPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
DrawMode drawMode = aCallbacks ? DrawMode::GLYPH_PATH :
DrawMode::GLYPH_FILL;
if (aCallbacks) {
aCallbacks->NotifyBeforeText(aTextColor);
- aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
+ aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aRange,
aProvider, aAdvanceWidth, aContextPaint, aCallbacks);
aCallbacks->NotifyAfterText();
} else {
aCtx->SetColor(Color::FromABGR(aTextColor));
- aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength,
+ aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aRange,
aProvider, aAdvanceWidth, aContextPaint);
}
}
void
nsTextFrame::DrawTextRun(gfxContext* const aCtx,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
PropertyProvider& aProvider,
nscolor aTextColor,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
gfxTextContextPaint* aContextPaint,
nsTextFrame::DrawPathCallbacks* aCallbacks)
{
- ::DrawTextRun(mTextRun, aCtx, aTextBaselinePt, aOffset, aLength, &aProvider,
+ ::DrawTextRun(mTextRun, aCtx, aTextBaselinePt, aRange, &aProvider,
aTextColor, &aAdvanceWidth, aContextPaint, aCallbacks);
if (aDrawSoftHyphen) {
// Don't use ctx as the context, because we need a reference context here,
// ctx may be transformed.
nsAutoPtr<gfxTextRun> hyphenTextRun(GetHyphenTextRun(mTextRun, nullptr, this));
if (hyphenTextRun.get()) {
// For right-to-left text runs, the soft-hyphen is positioned at the left
// of the text, minus its own width
- gfxFloat hyphenBaselineX = aTextBaselinePt.x + mTextRun->GetDirection() * aAdvanceWidth -
+ gfxFloat hyphenBaselineX =
(mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth() : 0);
::DrawTextRun(hyphenTextRun.get(), aCtx,
gfxPoint(hyphenBaselineX, aTextBaselinePt.y),
- 0, hyphenTextRun->GetLength(),
+ Range(hyphenTextRun.get()),
nullptr, aTextColor, nullptr, aContextPaint, aCallbacks);
}
}
}
void
nsTextFrame::DrawTextRunAndDecorations(
gfxContext* const aCtx, const gfxRect& aDirtyRect,
const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
const TextDecorations& aDecorations,
const nscolor* const aDecorationOverrideColor,
@@ -6744,21 +6739,21 @@ nsTextFrame::DrawTextRunAndDecorations(
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
decorationOffsetDir * metrics.maxAscent,
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
eNormalDecoration, aCallbacks, verticalRun);
}
// CSS 2.1 mandates that text be painted after over/underlines, and *then*
// line-throughs
- DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aTextColor,
+ DrawTextRun(aCtx, aTextBaselinePt, aRange, aProvider, aTextColor,
aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks);
// Emphasis marks
- DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aOffset, aLength,
+ DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aRange,
aDecorationOverrideColor, aProvider);
// Line-throughs
for (uint32_t i = aDecorations.mStrikes.Length(); i-- > 0; ) {
const LineDecoration& dec = aDecorations.mStrikes[i];
if (dec.mStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
continue;
}
@@ -6779,17 +6774,17 @@ nsTextFrame::DrawTextRunAndDecorations(
dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
}
}
void
nsTextFrame::DrawText(
gfxContext* const aCtx, const gfxRect& aDirtyRect,
const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
const nscolor* const aDecorationOverrideColor,
gfxTextContextPaint* aContextPaint,
@@ -6800,22 +6795,22 @@ nsTextFrame::DrawText(
aCallbacks ? eUnresolvedColors : eResolvedColors,
decorations);
// Hide text decorations if we're currently hiding @font-face fallback text
const bool drawDecorations = !aProvider.GetFontGroup()->ShouldSkipDrawing() &&
(decorations.HasDecorationLines() ||
StyleText()->HasTextEmphasis());
if (drawDecorations) {
- DrawTextRunAndDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt, aOffset, aLength,
+ DrawTextRunAndDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt, aRange,
aProvider, aTextStyle, aTextColor, aClipEdges, aAdvanceWidth,
aDrawSoftHyphen, decorations,
aDecorationOverrideColor, aContextPaint, aCallbacks);
} else {
- DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider,
+ DrawTextRun(aCtx, aTextBaselinePt, aRange, aProvider,
aTextColor, aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks);
}
}
int16_t
nsTextFrame::GetSelectionStatus(int16_t* aSelectionFlags)
{
// get the selection controller
@@ -6859,26 +6854,26 @@ nsTextFrame::IsVisibleInSelection(nsISel
return found;
}
/**
* Compute the longest prefix of text whose width is <= aWidth. Return
* the length of the prefix. Also returns the width of the prefix in aFitWidth.
*/
static uint32_t
-CountCharsFit(gfxTextRun* aTextRun, uint32_t aStart, uint32_t aLength,
+CountCharsFit(gfxTextRun* aTextRun, gfxTextRun::Range aRange,
gfxFloat aWidth, PropertyProvider* aProvider,
gfxFloat* aFitWidth)
{
uint32_t last = 0;
gfxFloat width = 0;
- for (uint32_t i = 1; i <= aLength; ++i) {
- if (i == aLength || aTextRun->IsClusterStart(aStart + i)) {
- gfxFloat nextWidth = width +
- aTextRun->GetAdvanceWidth(aStart + last, i - last, aProvider);
+ for (uint32_t i = 1; i <= aRange.Length(); ++i) {
+ if (i == aRange.Length() || aTextRun->IsClusterStart(aRange.start + i)) {
+ gfxTextRun::Range range(aRange.start + last, aRange.start + i);
+ gfxFloat nextWidth = width + aTextRun->GetAdvanceWidth(range, aProvider);
if (nextWidth > aWidth)
break;
last = i;
width = nextWidth;
}
}
*aFitWidth = width;
return last;
@@ -6908,23 +6903,23 @@ nsTextFrame::GetCharacterOffsetAtFramePo
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
// Trim leading but not trailing whitespace if possible
provider.InitializeForDisplay(false);
gfxFloat width = mTextRun->IsVertical()
? (mTextRun->IsInlineReversed() ? mRect.height - aPoint.y : aPoint.y)
: (mTextRun->IsInlineReversed() ? mRect.width - aPoint.x : aPoint.x);
gfxFloat fitWidth;
- uint32_t skippedLength = ComputeTransformedLength(provider);
-
- uint32_t charsFit = CountCharsFit(mTextRun,
- provider.GetStart().GetSkippedOffset(), skippedLength, width, &provider, &fitWidth);
+ Range skippedRange = ComputeTransformedRange(provider);
+
+ uint32_t charsFit = CountCharsFit(mTextRun, skippedRange,
+ width, &provider, &fitWidth);
int32_t selectedOffset;
- if (charsFit < skippedLength) {
+ if (charsFit < skippedRange.Length()) {
// charsFit characters fitted, but no more could fit. See if we're
// more than halfway through the cluster.. If we are, choose the next
// cluster.
gfxSkipCharsIterator extraCluster(provider.GetStart());
extraCluster.AdvanceSkipped(charsFit);
bool allowSplitLigature = true; // Allow selection of partial ligature...
@@ -6938,30 +6933,31 @@ nsTextFrame::GetCharacterOffsetAtFramePo
gfxFontUtils::IsRegionalIndicator
(SURROGATE_TO_UCS4(frag->CharAt(offs), frag->CharAt(offs + 1)))) {
allowSplitLigature = false;
if (extraCluster.GetSkippedOffset() > 1 &&
!mTextRun->IsLigatureGroupStart(extraCluster.GetSkippedOffset())) {
// CountCharsFit() left us in the middle of the flag; back up over the
// first character of the ligature, and adjust fitWidth accordingly.
extraCluster.AdvanceSkipped(-2); // it's a surrogate pair: 2 code units
- fitWidth -= mTextRun->GetAdvanceWidth(extraCluster.GetSkippedOffset(),
- 2, &provider);
+ fitWidth -= mTextRun->GetAdvanceWidth(
+ Range(extraCluster.GetSkippedOffset(),
+ extraCluster.GetSkippedOffset() + 2), &provider);
}
}
gfxSkipCharsIterator extraClusterLastChar(extraCluster);
FindClusterEnd(mTextRun,
provider.GetStart().GetOriginalOffset() + provider.GetOriginalLength(),
&extraClusterLastChar, allowSplitLigature);
PropertyProvider::Spacing spacing;
+ Range extraClusterRange(extraCluster.GetSkippedOffset(),
+ extraClusterLastChar.GetSkippedOffset() + 1);
gfxFloat charWidth =
- mTextRun->GetAdvanceWidth(extraCluster.GetSkippedOffset(),
- GetSkippedDistance(extraCluster, extraClusterLastChar) + 1,
- &provider, &spacing);
+ mTextRun->GetAdvanceWidth(extraClusterRange, &provider, &spacing);
charWidth -= spacing.mBefore + spacing.mAfter;
selectedOffset = !aForInsertionPoint ||
width <= fitWidth + spacing.mBefore + charWidth/2
? extraCluster.GetOriginalOffset()
: extraClusterLastChar.GetOriginalOffset() + 1;
} else {
// All characters fitted, we're at (or beyond) the end of the text.
// XXX This could be some pathological situation where negative spacing
@@ -7149,20 +7145,19 @@ nsTextFrame::GetPointFromOffset(int32_t
if (inOffset < trimmedEnd &&
!iter.IsOriginalCharSkipped() &&
!mTextRun->IsClusterStart(iter.GetSkippedOffset())) {
NS_WARNING("GetPointFromOffset called for non-cluster boundary");
FindClusterStart(mTextRun, trimmedOffset, &iter);
}
- gfxFloat advance =
- mTextRun->GetAdvanceWidth(properties.GetStart().GetSkippedOffset(),
- GetSkippedDistance(properties.GetStart(), iter),
- &properties);
+ Range range(properties.GetStart().GetSkippedOffset(),
+ iter.GetSkippedOffset());
+ gfxFloat advance = mTextRun->GetAdvanceWidth(range, &properties);
nscoord iSize = NSToCoordCeilClamped(advance);
if (mTextRun->IsVertical()) {
if (mTextRun->IsInlineReversed()) {
outPoint->y = mRect.height - iSize;
} else {
outPoint->y = iSize;
}
@@ -7854,17 +7849,17 @@ nsTextFrame::AddInlineMinISizeForFlow(ns
FindStartAfterSkippingWhitespace(&provider, aData, textStyle, &iter, flowEndInTextRun);
AutoTArray<bool,BIG_TEXT_NODE_SIZE> hyphBuffer;
bool *hyphBreakBefore = nullptr;
if (hyphenating) {
hyphBreakBefore = hyphBuffer.AppendElements(flowEndInTextRun - start,
fallible);
if (hyphBreakBefore) {
- provider.GetHyphenationBreaks(start, flowEndInTextRun - start,
+ provider.GetHyphenationBreaks(Range(start, flowEndInTextRun),
hyphBreakBefore);
}
}
for (uint32_t i = start, wordStart = start; i <= flowEndInTextRun; ++i) {
bool preformattedNewline = false;
bool preformattedTab = false;
if (i < flowEndInTextRun) {
@@ -7879,45 +7874,42 @@ nsTextFrame::AddInlineMinISizeForFlow(ns
(!hyphBreakBefore || !hyphBreakBefore[i - start]))
{
// we can't break here (and it's not the end of the flow)
continue;
}
}
if (i > wordStart) {
- nscoord width =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(wordStart, i - wordStart,
- &provider));
+ nscoord width = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(wordStart, i), &provider));
width = std::max(0, width);
aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, width);
aData->atStartOfLine = false;
if (collapseWhitespace) {
uint32_t trimStart = GetEndOfTrimmedText(frag, textStyle, wordStart, i, &iter);
if (trimStart == start) {
// This is *all* trimmable whitespace, so whatever trailingWhitespace
// we saw previously is still trailing...
aData->trailingWhitespace += width;
} else {
// Some non-whitespace so the old trailingWhitespace is no longer trailing
- nscoord wsWidth =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(trimStart,
- i - trimStart,
- &provider));
+ nscoord wsWidth = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(trimStart, i), &provider));
aData->trailingWhitespace = std::max(0, wsWidth);
}
} else {
aData->trailingWhitespace = 0;
}
}
if (preformattedTab) {
PropertyProvider::Spacing spacing;
- provider.GetSpacing(i, 1, &spacing);
+ provider.GetSpacing(Range(i, i + 1), &spacing);
aData->currentLine += nscoord(spacing.mBefore);
gfxFloat afterTab =
AdvanceToNextTab(aData->currentLine, this,
textRun, &tabWidth);
aData->currentLine = nscoord(afterTab + spacing.mAfter);
wordStart = i + 1;
} else if (i < flowEndInTextRun ||
(i == textRun->GetLength() &&
@@ -8035,44 +8027,41 @@ nsTextFrame::AddInlinePrefISizeForFlow(n
preformattedTab = preformatTabs && textRun->CharIsTab(i);
if (!preformattedNewline && !preformattedTab) {
// we needn't break here (and it's not the end of the flow)
continue;
}
}
if (i > lineStart) {
- nscoord width =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(lineStart, i - lineStart,
- &provider));
+ nscoord width = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(lineStart, i), &provider));
width = std::max(0, width);
aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, width);
if (collapseWhitespace) {
uint32_t trimStart = GetEndOfTrimmedText(frag, textStyle, lineStart, i, &iter);
if (trimStart == start) {
// This is *all* trimmable whitespace, so whatever trailingWhitespace
// we saw previously is still trailing...
aData->trailingWhitespace += width;
} else {
// Some non-whitespace so the old trailingWhitespace is no longer trailing
- nscoord wsWidth =
- NSToCoordCeilClamped(textRun->GetAdvanceWidth(trimStart,
- i - trimStart,
- &provider));
+ nscoord wsWidth = NSToCoordCeilClamped(
+ textRun->GetAdvanceWidth(Range(trimStart, i), &provider));
aData->trailingWhitespace = std::max(0, wsWidth);
}
} else {
aData->trailingWhitespace = 0;
}
}
if (preformattedTab) {
PropertyProvider::Spacing spacing;
- provider.GetSpacing(i, 1, &spacing);
+ provider.GetSpacing(Range(i, i + 1), &spacing);
aData->currentLine += nscoord(spacing.mBefore);
gfxFloat afterTab =
AdvanceToNextTab(aData->currentLine, this,
textRun, &tabWidth);
aData->currentLine = nscoord(afterTab + spacing.mAfter);
lineStart = i + 1;
} else if (preformattedNewline) {
aData->ForceBreak();
@@ -8170,18 +8159,17 @@ nsTextFrame::ComputeTightBounds(DrawTarg
return nsRect(0, 0, 0, 0);
PropertyProvider provider(const_cast<nsTextFrame*>(this), iter,
nsTextFrame::eInflated);
// Trim trailing whitespace
provider.InitializeForDisplay(true);
gfxTextRun::Metrics metrics =
- mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
- ComputeTransformedLength(provider),
+ mTextRun->MeasureText(ComputeTransformedRange(provider),
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
aDrawTarget, &provider);
if (GetWritingMode().IsLineInverted()) {
metrics.mBoundingBox.y = -metrics.mBoundingBox.YMost();
}
// mAscent should be the same as metrics.mAscent, but it's what we use to
// paint so that's the one we'll use.
nsRect boundingBox = RoundOut(metrics.mBoundingBox);
@@ -8204,18 +8192,17 @@ nsTextFrame::GetPrefWidthTightBounds(nsR
if (!mTextRun)
return NS_ERROR_FAILURE;
PropertyProvider provider(const_cast<nsTextFrame*>(this), iter,
nsTextFrame::eInflated);
provider.InitializeForMeasure();
gfxTextRun::Metrics metrics =
- mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
- ComputeTransformedLength(provider),
+ mTextRun->MeasureText(ComputeTransformedRange(provider),
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
aContext->GetDrawTarget(), &provider);
// Round it like nsTextFrame::ComputeTightBounds() to ensure consistency.
*aX = NSToCoordFloor(metrics.mBoundingBox.x);
*aXMost = NSToCoordCeil(metrics.mBoundingBox.XMost());
return NS_OK;
}
@@ -9026,17 +9013,18 @@ nsTextFrame::ReflowText(nsLineLayout& aL
// Compute space and letter counts for justification, if required
if (!textStyle->WhiteSpaceIsSignificant() &&
(lineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
shouldSuppressLineBreak) &&
!lineContainer->IsSVGText()) {
AddStateBits(TEXT_JUSTIFICATION_ENABLED);
- provider.ComputeJustification(offset, charsFit);
+ provider.ComputeJustification(Range(uint32_t(offset),
+ uint32_t(offset + charsFit)));
aLineLayout.SetJustificationInfo(provider.GetJustificationInfo());
}
SetLength(contentLength, &aLineLayout, ALLOW_FRAME_CREATION_AND_DESTRUCTION);
InvalidateFrame();
#ifdef NOISY_REFLOW
@@ -9084,23 +9072,24 @@ nsTextFrame::TrimTrailingWhiteSpace(Draw
trimmed.GetEnd() < GetContentEnd()) {
gfxSkipCharsIterator end = trimmedEndIter;
uint32_t endOffset = end.ConvertOriginalToSkipped(GetContentOffset() + contentLength);
if (trimmedEnd < endOffset) {
// We can't be dealing with tabs here ... they wouldn't be trimmed. So it's
// OK to pass null for the line container.
PropertyProvider provider(mTextRun, textStyle, frag, this, start, contentLength,
nullptr, 0, nsTextFrame::eInflated);
- delta = mTextRun->GetAdvanceWidth(trimmedEnd, endOffset - trimmedEnd, &provider);
+ delta = mTextRun->
+ GetAdvanceWidth(Range(trimmedEnd, endOffset), &provider);
result.mChanged = true;
}
}
gfxFloat advanceDelta;
- mTextRun->SetLineBreaks(trimmedStart, trimmedEnd - trimmedStart,
+ mTextRun->SetLineBreaks(Range(trimmedStart, trimmedEnd),
(GetStateBits() & TEXT_START_OF_LINE) != 0, true,
&advanceDelta);
if (advanceDelta != 0) {
result.mChanged = true;
}
// aDeltaWidth is *subtracted* from our width.
// If advanceDelta is positive then setting the line break made us longer,
@@ -9140,18 +9129,17 @@ nsTextFrame::RecomputeOverflow(nsIFrame*
if (!mTextRun)
return result;
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
// Don't trim trailing space, in case we need to paint it as selected.
provider.InitializeForDisplay(false);
gfxTextRun::Metrics textMetrics =
- mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
- ComputeTransformedLength(provider),
+ mTextRun->MeasureText(ComputeTransformedRange(provider),
gfxFont::LOOSE_INK_EXTENTS, nullptr,
&provider);
if (GetWritingMode().IsLineInverted()) {
textMetrics.mBoundingBox.y = -textMetrics.mBoundingBox.YMost();
}
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
boundingBox += nsPoint(0, mAscent);
if (mTextRun->IsVertical()) {
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -40,16 +40,17 @@ public:
};
class nsTextFrame : public nsTextFrameBase {
typedef mozilla::TextRangeStyle TextRangeStyle;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::Point Point;
typedef mozilla::gfx::Rect Rect;
typedef mozilla::gfx::Size Size;
+ typedef gfxTextRun::Range Range;
public:
NS_DECL_QUERYFRAME_TARGET(nsTextFrame)
NS_DECL_FRAMEARENA_HELPERS
friend class nsContinuingTextFrame;
friend class nsDisplayTextGeometry;
friend class nsDisplayText;
@@ -401,56 +402,53 @@ public:
// helper: paint text frame when we're impacted by at least one selection.
// Return false if the text was not painted and we should continue with
// the fast path.
bool PaintTextWithSelection(gfxContext* aCtx,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset,
- uint32_t aContentLength,
+ Range aRange,
nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxTextContextPaint* aContextPaint,
DrawPathCallbacks* aCallbacks);
// helper: paint text with foreground and background colors determined
// by selection(s). Also computes a mask of all selection types applying to
// our text, returned in aAllTypes.
// Return false if the text was not painted and we should continue with
// the fast path.
bool PaintTextWithSelectionColors(gfxContext* aCtx,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset,
- uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle,
SelectionDetails* aDetails,
SelectionType* aAllTypes,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
DrawPathCallbacks* aCallbacks);
// helper: paint text decorations for text selected by aSelectionType
void PaintTextSelectionDecorations(gfxContext* aCtx,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
const gfxRect& aDirtyRect,
PropertyProvider& aProvider,
- uint32_t aContentOffset,
- uint32_t aContentLength,
+ Range aContentRange,
nsTextPaintStyle& aTextPaintStyle,
SelectionDetails* aDetails,
SelectionType aSelectionType,
DrawPathCallbacks* aCallbacks);
void DrawEmphasisMarks(gfxContext* aContext,
mozilla::WritingMode aWM,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nscolor* aDecorationOverrideColor,
PropertyProvider& aProvider);
virtual nscolor GetCaretColorAt(int32_t aOffset) override;
int16_t GetSelectionStatus(int16_t* aSelectionFlags);
int32_t GetContentOffset() const { return mContentOffset; }
@@ -593,32 +591,31 @@ protected:
nsRect* aVisualOverflowRect,
bool aIncludeTextDecorations);
// Update information of emphasis marks, and return the visial
// overflow rect of the emphasis marks.
nsRect UpdateTextEmphasis(mozilla::WritingMode aWM,
PropertyProvider& aProvider);
- void PaintOneShadow(uint32_t aOffset,
- uint32_t aLength,
+ void PaintOneShadow(Range aRange,
nsCSSShadowItem* aShadowDetails,
PropertyProvider* aProvider,
const nsRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
gfxContext* aCtx,
const nscolor& aForegroundColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
nscoord aLeftSideOffset,
gfxRect& aBoundingBox,
uint32_t aBlurFlags);
void PaintShadows(nsCSSShadowArray* aShadow,
- uint32_t aOffset, uint32_t aLength,
+ Range aRange,
const nsRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
nscoord aLeftEdgeOffset,
PropertyProvider& aProvider,
nscolor aForegroundColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxContext* aCtx);
@@ -694,48 +691,45 @@ protected:
eUnresolvedColors
};
void GetTextDecorations(nsPresContext* aPresContext,
TextDecorationColorResolution aColorResolution,
TextDecorations& aDecorations);
void DrawTextRun(gfxContext* const aCtx,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset,
- uint32_t aLength,
+ Range aRange,
PropertyProvider& aProvider,
nscolor aTextColor,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
gfxTextContextPaint* aContextPaint,
DrawPathCallbacks* aCallbacks);
void DrawTextRunAndDecorations(gfxContext* const aCtx,
const gfxRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset,
- uint32_t aLength,
+ Range aRange,
PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
const TextDecorations& aDecorations,
const nscolor* const aDecorationOverrideColor,
gfxTextContextPaint* aContextPaint,
DrawPathCallbacks* aCallbacks);
void DrawText(gfxContext* const aCtx,
const gfxRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
- uint32_t aOffset,
- uint32_t aLength,
+ Range aRange,
PropertyProvider& aProvider,
const nsTextPaintStyle& aTextStyle,
nscolor aTextColor,
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
gfxFloat& aAdvanceWidth,
bool aDrawSoftHyphen,
const nscolor* const aDecorationOverrideColor = nullptr,
gfxTextContextPaint* aContextPaint = nullptr,
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -64,21 +64,21 @@ nsTransformedTextRun::SetCapitalization(
return;
memset(mCapitalize.Elements(), 0, GetLength()*sizeof(bool));
}
memcpy(mCapitalize.Elements() + aStart, aCapitalization, aLength*sizeof(bool));
mNeedsRebuild = true;
}
bool
-nsTransformedTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
+nsTransformedTextRun::SetPotentialLineBreaks(Range aRange,
uint8_t* aBreakBefore)
{
bool changed =
- gfxTextRun::SetPotentialLineBreaks(aStart, aLength, aBreakBefore);
+ gfxTextRun::SetPotentialLineBreaks(aRange, aBreakBefore);
if (changed) {
mNeedsRebuild = true;
}
return changed;
}
size_t
nsTransformedTextRun::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
@@ -126,17 +126,17 @@ nsTransformingTextRunFactory::MakeTextRu
}
void
MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
const bool* aCharsToMerge, const bool* aDeletedChars)
{
aDest->ResetGlyphRuns();
- gfxTextRun::GlyphRunIterator iter(aSrc, 0, aSrc->GetLength());
+ gfxTextRun::GlyphRunIterator iter(aSrc, gfxTextRun::Range(aSrc));
uint32_t offset = 0;
AutoTArray<gfxTextRun::DetailedGlyph,2> glyphs;
while (iter.NextRun()) {
gfxTextRun::GlyphRun* run = iter.GetGlyphRun();
nsresult rv = aDest->AddGlyphRun(run->mFont, run->mMatchType,
offset, false, run->mOrientation);
if (NS_FAILED(rv))
return;
@@ -641,18 +641,18 @@ nsCaseTransformTextRunFactory::RebuildTe
child = cachedChild.get();
}
if (!child)
return;
// Copy potential linebreaks into child so they're preserved
// (and also child will be shaped appropriately)
NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(),
"Dropped characters or break-before values somewhere!");
- child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
- canBreakBeforeArray.Elements());
+ gfxTextRun::Range range(0, uint32_t(canBreakBeforeArray.Length()));
+ child->SetPotentialLineBreaks(range, canBreakBeforeArray.Elements());
if (transformedChild) {
transformedChild->FinishSettingProperties(aRefDrawTarget, aMFR);
}
if (mergeNeeded) {
// Now merge multiple characters into one multi-glyph character as required
// and deal with skipping deleted accent chars
NS_ASSERTION(charsToMergeArray.Length() == child->GetLength(),
@@ -661,11 +661,11 @@ nsCaseTransformTextRunFactory::RebuildTe
"destination length mismatch");
MergeCharactersInTextRun(aTextRun, child, charsToMergeArray.Elements(),
deletedCharsArray.Elements());
} else {
// No merging to do, so just copy; this produces a more optimized textrun.
// We can't steal the data because the child may be cached and stealing
// the data would break the cache.
aTextRun->ResetGlyphRuns();
- aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0);
+ aTextRun->CopyGlyphDataFrom(child, gfxTextRun::Range(child), 0);
}
}
--- a/layout/generic/nsTextRunTransformations.h
+++ b/layout/generic/nsTextRunTransformations.h
@@ -125,18 +125,17 @@ public:
~nsTransformedTextRun() {
if (mOwnsFactory) {
delete mFactory;
}
}
void SetCapitalization(uint32_t aStart, uint32_t aLength,
bool* aCapitalization);
- virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
- uint8_t* aBreakBefore);
+ virtual bool SetPotentialLineBreaks(Range aRange, uint8_t* aBreakBefore);
/**
* Called after SetCapitalization and SetPotentialLineBreaks
* are done and before we request any data from the textrun. Also always
* called after a Create.
*/
void FinishSettingProperties(mozilla::gfx::DrawTarget* aRefDrawTarget,
gfxMissingFontRecorder* aMFR)
{
--- a/layout/inspector/nsFontFaceList.cpp
+++ b/layout/inspector/nsFontFaceList.cpp
@@ -55,17 +55,18 @@ nsFontFaceList::GetLength(uint32_t *aLen
////////////////////////////////////////////////////////////////////////
// nsFontFaceList
nsresult
nsFontFaceList::AddFontsFromTextRun(gfxTextRun* aTextRun,
uint32_t aOffset, uint32_t aLength)
{
- gfxTextRun::GlyphRunIterator iter(aTextRun, aOffset, aLength);
+ gfxTextRun::Range range(aOffset, aOffset + aLength);
+ gfxTextRun::GlyphRunIterator iter(aTextRun, range);
while (iter.NextRun()) {
gfxFontEntry *fe = iter.GetGlyphRun()->mFont->GetFontEntry();
// if we have already listed this face, just make sure the match type is
// recorded
nsFontFace* existingFace =
static_cast<nsFontFace*>(mFontFaces.GetWeak(fe));
if (existingFace) {
existingFace->AddMatchType(iter.GetGlyphRun()->mMatchType);
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -2142,17 +2142,17 @@ nsMathMLChar::PaintForeground(nsPresCont
switch(mDraw)
{
case DRAW_NORMAL:
case DRAW_VARIANT:
// draw a single glyph (base size or size variant)
// XXXfredw verify if mGlyphs[0] is non-null to workaround bug 973322.
if (mGlyphs[0]) {
mGlyphs[0]->Draw(thebesContext, gfxPoint(0.0, mUnscaledAscent),
- DrawMode::GLYPH_FILL, 0, mGlyphs[0]->GetLength(),
+ DrawMode::GLYPH_FILL, Range(mGlyphs[0]),
nullptr, nullptr, nullptr);
}
break;
case DRAW_PARTS: {
// paint by parts
if (NS_STRETCH_DIRECTION_VERTICAL == mDirection)
PaintVertically(aPresContext, thebesContext, r, fgColor);
else if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection)
@@ -2299,17 +2299,17 @@ nsMathMLChar::PaintVertically(nsPresCont
else { // middle
clipRect.y = start[i];
clipRect.height = end[i] - start[i];
}
}
if (!clipRect.IsEmpty()) {
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
mGlyphs[i]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[i]->GetLength(),
+ DrawMode::GLYPH_FILL, Range(mGlyphs[i]),
nullptr, nullptr, nullptr);
}
}
}
///////////////
// fill the gap between top and middle, and between middle and bottom.
if (!mGlyphs[3]) { // null glue : draw a rule
@@ -2367,17 +2367,17 @@ nsMathMLChar::PaintVertically(nsPresCont
nscoord dy = std::max(end[i], aRect.y);
nscoord fillEnd = std::min(start[i+1], aRect.YMost());
while (dy < fillEnd) {
clipRect.y = dy;
clipRect.height = std::min(bm.ascent + bm.descent, fillEnd - dy);
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
dy += bm.ascent;
mGlyphs[3]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[3]->GetLength(),
+ DrawMode::GLYPH_FILL, Range(mGlyphs[3]),
nullptr, nullptr, nullptr);
dy += bm.descent;
}
}
}
#ifdef DEBUG
else {
for (i = 0; i < 2; ++i) {
@@ -2471,17 +2471,17 @@ nsMathMLChar::PaintHorizontally(nsPresCo
else { // middle
clipRect.x = start[i];
clipRect.width = end[i] - start[i];
}
}
if (!clipRect.IsEmpty()) {
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
mGlyphs[i]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[i]->GetLength(),
+ DrawMode::GLYPH_FILL, Range(mGlyphs[i]),
nullptr, nullptr, nullptr);
}
}
}
////////////////
// fill the gap between left and middle, and between middle and right.
if (!mGlyphs[3]) { // null glue : draw a rule
@@ -2537,17 +2537,17 @@ nsMathMLChar::PaintHorizontally(nsPresCo
nscoord dx = std::max(end[i], aRect.x);
nscoord fillEnd = std::min(start[i+1], aRect.XMost());
while (dx < fillEnd) {
clipRect.x = dx;
clipRect.width = std::min(bm.rightBearing - bm.leftBearing, fillEnd - dx);
AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect);
dx -= bm.leftBearing;
mGlyphs[3]->Draw(aThebesContext, gfxPoint(dx, dy),
- DrawMode::GLYPH_FILL, 0, mGlyphs[3]->GetLength(),
+ DrawMode::GLYPH_FILL, Range(mGlyphs[3]),
nullptr, nullptr, nullptr);
dx += bm.rightBearing;
}
}
}
#ifdef DEBUG
else { // no glue
for (i = 0; i < 2; ++i) {
--- a/layout/mathml/nsMathMLChar.h
+++ b/layout/mathml/nsMathMLChar.h
@@ -8,17 +8,17 @@
#include "nsAutoPtr.h"
#include "nsColor.h"
#include "nsMathMLOperators.h"
#include "nsPoint.h"
#include "nsRect.h"
#include "nsString.h"
#include "nsBoundingMetrics.h"
-#include "gfxFont.h"
+#include "gfxTextRun.h"
class nsGlyphTable;
class nsIFrame;
class nsDisplayListBuilder;
class nsDisplayListSet;
class nsPresContext;
class nsRenderingContext;
struct nsBoundingMetrics;
@@ -80,16 +80,17 @@ struct nsGlyphCode {
}
};
// Class used to handle stretchy symbols (accent, delimiter and boundary
// symbols).
class nsMathMLChar
{
public:
+ typedef gfxTextRun::Range Range;
typedef mozilla::gfx::DrawTarget DrawTarget;
// constructor and destructor
nsMathMLChar() {
MOZ_COUNT_CTOR(nsMathMLChar);
mStyleContext = nullptr;
mUnscaledAscent = 0;
mScaleX = mScaleY = 1.0;
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -55,44 +55,26 @@ using namespace mozilla::gfx;
// ============================================================================
// Utility functions
/**
* Using the specified gfxSkipCharsIterator, converts an offset and length
* in original char indexes to skipped char indexes.
*
* @param aIterator The gfxSkipCharsIterator to use for the conversion.
- * @param aOriginalOffset The original offset (input).
- * @param aOriginalLength The original length (input).
- * @param aSkippedOffset The skipped offset (output).
- * @param aSkippedLength The skipped length (output).
+ * @param aOriginalOffset The original offset.
+ * @param aOriginalLength The original length.
*/
-static void
+static gfxTextRun::Range
ConvertOriginalToSkipped(gfxSkipCharsIterator& aIterator,
- uint32_t aOriginalOffset, uint32_t aOriginalLength,
- uint32_t& aSkippedOffset, uint32_t& aSkippedLength)
+ uint32_t aOriginalOffset, uint32_t aOriginalLength)
{
- aSkippedOffset = aIterator.ConvertOriginalToSkipped(aOriginalOffset);
+ uint32_t start = aIterator.ConvertOriginalToSkipped(aOriginalOffset);
aIterator.AdvanceOriginal(aOriginalLength);
- aSkippedLength = aIterator.GetSkippedOffset() - aSkippedOffset;
-}
-
-/**
- * Using the specified gfxSkipCharsIterator, converts an offset and length
- * in original char indexes to skipped char indexes in place.
- *
- * @param aIterator The gfxSkipCharsIterator to use for the conversion.
- * @param aOriginalOffset The offset to convert from original to skipped.
- * @param aOriginalLength The length to convert from original to skipped.
- */
-static void
-ConvertOriginalToSkipped(gfxSkipCharsIterator& aIterator,
- uint32_t& aOffset, uint32_t& aLength)
-{
- ConvertOriginalToSkipped(aIterator, aOffset, aLength, aOffset, aLength);
+ return gfxTextRun::Range(start, aIterator.GetSkippedOffset());
}
/**
* Converts an nsPoint from app units to user space units using the specified
* nsPresContext and returns it as a gfxPoint.
*/
static gfxPoint
AppUnitsToGfxUnits(const nsPoint& aPoint, const nsPresContext* aContext)
@@ -152,25 +134,21 @@ Inside(const gfxRect& aRect, const gfxPo
*/
static void
GetAscentAndDescentInAppUnits(nsTextFrame* aFrame,
gfxFloat& aAscent, gfxFloat& aDescent)
{
gfxSkipCharsIterator it = aFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = aFrame->GetTextRun(nsTextFrame::eInflated);
- uint32_t offset, length;
- ConvertOriginalToSkipped(it,
- aFrame->GetContentOffset(),
- aFrame->GetContentLength(),
- offset, length);
+ gfxTextRun::Range range = ConvertOriginalToSkipped(
+ it, aFrame->GetContentOffset(), aFrame->GetContentLength());
gfxTextRun::Metrics metrics =
- textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS, nullptr,
- nullptr);
+ textRun->MeasureText(range, gfxFont::LOOSE_INK_EXTENTS, nullptr, nullptr);
aAscent = metrics.mAscent;
aDescent = metrics.mDescent;
}
/**
* Updates an interval by intersecting it with another interval.
* The intervals are specified using a start index and a length.
@@ -380,36 +358,36 @@ GetBaselinePosition(nsTextFrame* aFrame,
return (metrics.mAscent + metrics.mDescent) / 2.0;
}
NS_NOTREACHED("unexpected dominant-baseline value");
return aFrame->GetLogicalBaseline(writingMode);
}
/**
- * For a given text run, returns the number of skipped characters that comprise
+ * For a given text run, returns the range of skipped characters that comprise
* the ligature group and/or cluster that includes the character represented
* by the specified gfxSkipCharsIterator.
*
* @param aTextRun The text run to use for determining whether a given character
* is part of a ligature or cluster.
* @param aIterator The gfxSkipCharsIterator to use for the current position
* in the text run.
*/
-static uint32_t
-ClusterLength(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator)
+static gfxTextRun::Range
+ClusterRange(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator)
{
uint32_t start = aIterator.GetSkippedOffset();
uint32_t end = start + 1;
while (end < aTextRun->GetLength() &&
(!aTextRun->IsLigatureGroupStart(end) ||
!aTextRun->IsClusterStart(end))) {
end++;
}
- return end - start;
+ return gfxTextRun::Range(start, end);
}
/**
* Truncates an array to be at most the length of another array.
*
* @param aArrayToTruncate The array to truncate.
* @param aReferenceArray The array whose length will be used to truncate
* aArrayToTruncate to.
@@ -476,16 +454,18 @@ namespace mozilla {
* - The glyphs are not on a text path
* - The glyphs correspond to content within the one nsTextFrame
*
* A TextRenderedRunIterator produces TextRenderedRuns required for painting a
* whole SVGTextFrame.
*/
struct TextRenderedRun
{
+ typedef gfxTextRun::Range Range;
+
/**
* Constructs a TextRenderedRun that is uninitialized except for mFrame
* being null.
*/
TextRenderedRun()
: mFrame(nullptr)
{
}
@@ -933,40 +913,38 @@ TextRenderedRun::GetRunUserSpaceRect(nsP
nscoord above = vertical ? -self.x : -self.y;
nscoord below = vertical ? self.XMost() - rect.width
: self.YMost() - rect.height;
gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated);
// Get the content range for this rendered run.
- uint32_t offset, length;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- offset, length);
- if (length == 0) {
+ Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
+ if (range.Length() == 0) {
return r;
}
// Measure that range.
gfxTextRun::Metrics metrics =
- textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS,
- nullptr, nullptr);
+ textRun->MeasureText(range, gfxFont::LOOSE_INK_EXTENTS, nullptr, nullptr);
// Make sure it includes the font-box.
gfxRect fontBox(0, -metrics.mAscent,
metrics.mAdvanceWidth, metrics.mAscent + metrics.mDescent);
metrics.mBoundingBox.UnionRect(metrics.mBoundingBox, fontBox);
// Determine the rectangle that covers the rendered run's fill,
// taking into account the measured vertical overflow due to
// decorations.
nscoord baseline = metrics.mBoundingBox.y + metrics.mAscent;
gfxFloat x, width;
if (aFlags & eNoHorizontalOverflow) {
x = 0.0;
- width = textRun->GetAdvanceWidth(offset, length, nullptr);
+ width = textRun->GetAdvanceWidth(range, nullptr);
} else {
x = metrics.mBoundingBox.x;
width = metrics.mBoundingBox.width;
}
nsRect fillInAppUnits(x, baseline - above,
width, metrics.mBoundingBox.height + above + below);
if (textRun->IsVertical()) {
// Swap line-relative textMetrics dimensions to physical coordinates.
@@ -1053,67 +1031,63 @@ TextRenderedRun::GetClipEdges(nscoord& a
return;
}
gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated);
// Get the covered content offset/length for this rendered run in skipped
// characters, since that is what GetAdvanceWidth expects.
- uint32_t runOffset, runLength, frameOffset, frameLength;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- runOffset, runLength);
+ Range runRange = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
// Get the offset/length of the whole nsTextFrame.
- frameOffset = mFrame->GetContentOffset();
- frameLength = mFrame->GetContentLength();
+ uint32_t frameOffset = mFrame->GetContentOffset();
+ uint32_t frameLength = mFrame->GetContentLength();
// Trim the whole-nsTextFrame offset/length to remove any leading/trailing
// white space, as the nsTextFrame when painting does not include them when
// interpreting clip edges.
nsTextFrame::TrimmedOffsets trimmedOffsets =
mFrame->GetTrimmedOffsets(mFrame->GetContent()->GetText(), true);
TrimOffsets(frameOffset, frameLength, trimmedOffsets);
// Convert the trimmed whole-nsTextFrame offset/length into skipped
// characters.
- ConvertOriginalToSkipped(it, frameOffset, frameLength);
+ Range frameRange = ConvertOriginalToSkipped(it, frameOffset, frameLength);
// Measure the advance width in the text run between the start of
// frame's content and the start of the rendered run's content,
- nscoord startEdge =
- textRun->GetAdvanceWidth(frameOffset, runOffset - frameOffset, nullptr);
+ nscoord startEdge = textRun->
+ GetAdvanceWidth(Range(frameRange.start, runRange.start), nullptr);
// and between the end of the rendered run's content and the end
// of the frame's content.
- nscoord endEdge =
- textRun->GetAdvanceWidth(runOffset + runLength,
- frameOffset + frameLength - (runOffset + runLength),
- nullptr);
+ nscoord endEdge = textRun->
+ GetAdvanceWidth(Range(runRange.end, frameRange.end), nullptr);
if (textRun->IsRightToLeft()) {
aVisIStartEdge = endEdge;
aVisIEndEdge = startEdge;
} else {
aVisIStartEdge = startEdge;
aVisIEndEdge = endEdge;
}
}
nscoord
TextRenderedRun::GetAdvanceWidth() const
{
gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated);
- uint32_t offset, length;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- offset, length);
-
- return textRun->GetAdvanceWidth(offset, length, nullptr);
+ Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
+
+ return textRun->GetAdvanceWidth(range, nullptr);
}
int32_t
TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext,
const gfxPoint& aPoint) const
{
if (mTextFrameContentLength == 0) {
return -1;
@@ -1154,37 +1128,34 @@ TextRenderedRun::GetCharNumAtPosition(ns
}
}
gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated);
// Next check that the point lies horizontally within the left and right
// edges of the text.
- uint32_t offset, length;
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength,
- offset, length);
+ Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset,
+ mTextFrameContentLength);
gfxFloat runAdvance =
- aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length,
- nullptr));
+ aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(range, nullptr));
gfxFloat pos = writingMode.IsVertical() ? p.y : p.x;
if (pos < 0 || pos >= runAdvance) {
return -1;
}
// Finally, measure progressively smaller portions of the rendered run to
// find which glyph it lies within. This will need to change once we
// support letter-spacing and word-spacing.
bool rtl = textRun->IsRightToLeft();
for (int32_t i = mTextFrameContentLength - 1; i >= 0; i--) {
- ConvertOriginalToSkipped(it, mTextFrameContentOffset, i, offset, length);
+ range = ConvertOriginalToSkipped(it, mTextFrameContentOffset, i);
gfxFloat advance =
- aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length,
- nullptr));
+ aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(range, nullptr));
if ((rtl && pos < runAdvance - advance) ||
(!rtl && pos >= advance)) {
return i;
}
}
return -1;
}
@@ -2132,16 +2103,18 @@ TextRenderedRunIterator::First()
// -----------------------------------------------------------------------------
// CharIterator
/**
* Iterator for characters within an SVGTextFrame.
*/
class CharIterator
{
+ typedef gfxTextRun::Range Range;
+
public:
/**
* Values for the aFilter argument of the constructor, to indicate which
* characters we should be iterating over.
*/
enum CharacterFilter {
// Iterate over all original characters from the DOM that are within valid
// text content elements.
@@ -2623,55 +2596,56 @@ CharIterator::GetOriginalGlyphOffsets(ui
gfxFloat
CharIterator::GetGlyphAdvance(nsPresContext* aContext) const
{
uint32_t offset, length;
GetOriginalGlyphOffsets(offset, length);
gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated);
- ConvertOriginalToSkipped(it, offset, length);
+ Range range = ConvertOriginalToSkipped(it, offset, length);
float cssPxPerDevPx = aContext->
AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel());
- gfxFloat advance = mTextRun->GetAdvanceWidth(offset, length, nullptr);
+ gfxFloat advance = mTextRun->GetAdvanceWidth(range, nullptr);
return aContext->AppUnitsToGfxUnits(advance) *
mLengthAdjustScaleFactor * cssPxPerDevPx;
}
gfxFloat
CharIterator::GetAdvance(nsPresContext* aContext) const
{
float cssPxPerDevPx = aContext->
AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel());
- gfxFloat advance =
- mTextRun->GetAdvanceWidth(mSkipCharsIterator.GetSkippedOffset(), 1, nullptr);
+ uint32_t offset = mSkipCharsIterator.GetSkippedOffset();
+ gfxFloat advance = mTextRun->
+ GetAdvanceWidth(Range(offset, offset + 1), nullptr);
return aContext->AppUnitsToGfxUnits(advance) *
mLengthAdjustScaleFactor * cssPxPerDevPx;
}
gfxFloat
CharIterator::GetGlyphPartialAdvance(uint32_t aPartLength,
nsPresContext* aContext) const
{
uint32_t offset, length;
GetOriginalGlyphOffsets(offset, length);
NS_ASSERTION(aPartLength <= length, "invalid aPartLength value");
length = aPartLength;
gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated);
- ConvertOriginalToSkipped(it, offset, length);
+ Range range = ConvertOriginalToSkipped(it, offset, length);
float cssPxPerDevPx = aContext->
AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel());
- gfxFloat advance = mTextRun->GetAdvanceWidth(offset, length, nullptr);
+ gfxFloat advance = mTextRun->GetAdvanceWidth(range, nullptr);
return aContext->AppUnitsToGfxUnits(advance) *
mLengthAdjustScaleFactor * cssPxPerDevPx;
}
bool
CharIterator::NextCharacter()
{
if (AtEnd()) {
@@ -4213,20 +4187,20 @@ SVGTextFrame::GetSubStringLength(nsICont
if (length != 0) {
// Convert offset into an index into the frame.
offset += run.mTextFrameContentOffset - run.mTextElementCharIndex;
gfxSkipCharsIterator it =
run.mFrame->EnsureTextRun(nsTextFrame::eInflated);
gfxTextRun* textRun = run.mFrame->GetTextRun(nsTextFrame::eInflated);
- ConvertOriginalToSkipped(it, offset, length);
+ Range range = ConvertOriginalToSkipped(it, offset, length);
// Accumulate the advance.
- textLength += textRun->GetAdvanceWidth(offset, length, nullptr);
+ textLength += textRun->GetAdvanceWidth(range, nullptr);
}
run = it.Next();
}
nsPresContext* presContext = PresContext();
float cssPxPerDevPx = presContext->
AppUnitsToFloatCSSPixels(presContext->AppUnitsPerDevPixel());
@@ -4715,34 +4689,34 @@ SVGTextFrame::DetermineCharPositions(nsT
}
// If a ligature was started in the previous frame, we should record
// the ligature's start position, not any partial position.
while (it.GetOriginalOffset() < frame->GetContentEnd() &&
!it.IsOriginalCharSkipped() &&
(!textRun->IsLigatureGroupStart(it.GetSkippedOffset()) ||
!textRun->IsClusterStart(it.GetSkippedOffset()))) {
- nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(), 1,
- nullptr);
+ uint32_t offset = it.GetSkippedOffset();
+ nscoord advance = textRun->
+ GetAdvanceWidth(Range(offset, offset + 1), nullptr);
(textRun->IsVertical() ? position.y : position.x) +=
textRun->IsRightToLeft() ? -advance : advance;
aPositions.AppendElement(lastPosition);
it.AdvanceOriginal(1);
}
// The meat of the text frame.
while (it.GetOriginalOffset() < frame->GetContentEnd()) {
aPositions.AppendElement(position);
if (!it.IsOriginalCharSkipped() &&
textRun->IsLigatureGroupStart(it.GetSkippedOffset()) &&
textRun->IsClusterStart(it.GetSkippedOffset())) {
// A real visible character.
- uint32_t length = ClusterLength(textRun, it);
- nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(),
- length, nullptr);
+ nscoord advance = textRun->
+ GetAdvanceWidth(ClusterRange(textRun, it), nullptr);
(textRun->IsVertical() ? position.y : position.x) +=
textRun->IsRightToLeft() ? -advance : advance;
lastPosition = position;
}
it.AdvanceOriginal(1);
}
}
--- a/layout/svg/SVGTextFrame.h
+++ b/layout/svg/SVGTextFrame.h
@@ -7,16 +7,17 @@
#define MOZILLA_SVGTEXTFRAME_H
#include "mozilla/Attributes.h"
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/2D.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "gfxSVGGlyphs.h"
+#include "gfxTextRun.h"
#include "nsIContent.h" // for GetContent
#include "nsStubMutationObserver.h"
#include "nsSVGPaintServerFrame.h"
class gfxContext;
class nsDisplaySVGText;
class SVGTextFrame;
class nsTextFrame;
@@ -253,16 +254,17 @@ class SVGTextFrame final : public SVGTex
friend class mozilla::GlyphMetricsUpdater;
friend class mozilla::TextFrameIterator;
friend class mozilla::TextNodeCorrespondenceRecorder;
friend struct mozilla::TextRenderedRun;
friend class mozilla::TextRenderedRunIterator;
friend class MutationObserver;
friend class nsDisplaySVGText;
+ typedef gfxTextRun::Range Range;
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::Path Path;
typedef mozilla::gfx::Point Point;
typedef mozilla::SVGTextContextPaint SVGTextContextPaint;
protected:
explicit SVGTextFrame(nsStyleContext* aContext)
: SVGTextFrameBase(aContext),