Bug 1056516 - use HyphenType to store different types of hyphenations. draft
authorJeremy Chen <jeremychen@mozilla.com>
Sun, 19 Feb 2017 17:36:55 +0800
changeset 486701 95f62f8176cffe20e2b3633ee0858b8050519cd8
parent 486700 0d3884ccad2a986f04f3a1952b6150d87a73d76b
child 486702 36f2d0d0c4598ede924bc272fb6d252309c15907
push id46037
push userjichen@mozilla.com
push dateSun, 19 Feb 2017 09:37:40 +0000
bugs1056516
milestone54.0a1
Bug 1056516 - use HyphenType to store different types of hyphenations. MozReview-Commit-ID: LUVboirjZjb
gfx/src/nsFontMetrics.cpp
gfx/thebes/gfxTextRun.cpp
gfx/thebes/gfxTextRun.h
layout/generic/nsTextFrame.cpp
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -79,17 +79,17 @@ private:
     }
 
     RefPtr<gfxTextRun> mTextRun;
 };
 
 class StubPropertyProvider : public gfxTextRun::PropertyProvider {
 public:
     virtual void GetHyphenationBreaks(gfxTextRun::Range aRange,
-                                      nsTArray<bool>& aBreakBefore) {
+                                      nsTArray<gfxTextRun::HyphenType>& aBreakBefore) {
         NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
     }
     virtual mozilla::StyleHyphens GetHyphensOption() {
         NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
         return mozilla::StyleHyphens::None;
     }
     virtual gfxFloat GetHyphenWidth() {
         NS_ERROR("This shouldn't be called because we never enable hyphens");
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -854,17 +854,17 @@ gfxTextRun::BreakAndMeasureText(uint32_t
 
     Range bufferRange(aStart, aStart + aMaxLength);
     AutoTArray<PropertyProvider::Spacing, 100> spacingBuffer;
     spacingBuffer.AppendElements(bufferRange.Length());
     bool haveSpacing = aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING) != 0;
     if (haveSpacing) {
         GetAdjustedSpacing(this, bufferRange, aProvider, spacingBuffer.Elements());
     }
-    AutoTArray<bool, 100> hyphenBuffer;
+    AutoTArray<HyphenType, 100> hyphenBuffer;
     hyphenBuffer.AppendElements(bufferRange.Length());
     bool haveHyphenation = aProvider &&
         (aProvider->GetHyphensOption() == StyleHyphens::Auto ||
          (aProvider->GetHyphensOption() == StyleHyphens::Manual &&
           (mFlags & gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS) != 0));
     if (haveHyphenation) {
         aProvider->GetHyphenationBreaks(bufferRange, hyphenBuffer);
     }
@@ -889,18 +889,19 @@ gfxTextRun::BreakAndMeasureText(uint32_t
     for (i = aStart; i < end; ++i) {
         // 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 - bufferRange.start];
+            bool atHyphenationBreak =
+                !atNaturalBreak && haveHyphenation &&
+                hyphenBuffer[i - bufferRange.start] != HyphenType::None;
             bool atBreak = atNaturalBreak || atHyphenationBreak;
             bool wordWrapping =
                 aCanWordWrap && mCharacterGlyphs[i].IsClusterStart() &&
                 *aBreakPriority <= gfxBreakPriority::eWordWrapBreak;
 
             if (atBreak || wordWrapping) {
                 gfxFloat hyphenatedAdvance = advance;
                 if (atHyphenationBreak) {
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -170,32 +170,38 @@ public:
      * 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(Range aRange,
                                         const uint8_t* aBreakBefore);
 
+    enum class HyphenType : uint8_t {
+      None,
+      Manual,
+      Auto
+    };
+
     /**
      * 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(Range aRange,
-                                          nsTArray<bool>& aBreakBefore) = 0;
+                                          nsTArray<HyphenType>& aBreakBefore) = 0;
 
         // Returns the provider's hyphenation setting, so callers can decide
         // whether it is necessary to call GetHyphenationBreaks.
         // Result is an StyleHyphens value.
         virtual mozilla::StyleHyphens GetHyphensOption() = 0;
 
         // Returns the extra width that will be consumed by a hyphen. This should
         // be constant for a given textrun.
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -3072,16 +3072,17 @@ static bool IsInBounds(const gfxSkipChar
   gfxSkipCharsIterator iter(aStart);
   iter.AdvanceOriginal(aContentLength);
   return iter.GetSkippedOffset() >= aRange.end;
 }
 #endif
 
 class MOZ_STACK_CLASS PropertyProvider : public gfxTextRun::PropertyProvider {
   typedef gfxTextRun::Range Range;
+  typedef gfxTextRun::HyphenType HyphenType;
 
 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
@@ -3136,17 +3137,17 @@ public:
 
   // Call this after construction if you're not going to reflow the text
   void InitializeForDisplay(bool aTrimAfter);
 
   void InitializeForMeasure();
 
   virtual void GetSpacing(Range aRange, Spacing* aSpacing);
   virtual gfxFloat GetHyphenWidth();
-  virtual void GetHyphenationBreaks(Range aRange, nsTArray<bool>& aBreakBefore);
+  virtual void GetHyphenationBreaks(Range aRange, nsTArray<HyphenType>& aBreakBefore);
   virtual StyleHyphens GetHyphensOption() {
     return mTextStyle->mHyphens;
   }
 
   virtual already_AddRefed<DrawTarget> GetDrawTarget() {
     return CreateReferenceDrawTarget(GetFrame());
   }
 
@@ -3574,25 +3575,27 @@ PropertyProvider::GetHyphenWidth()
 {
   if (mHyphenWidth < 0) {
     mHyphenWidth = GetFontGroup()->GetHyphenWidth(this);
   }
   return mHyphenWidth + mLetterSpacing;
 }
 
 void
-PropertyProvider::GetHyphenationBreaks(Range aRange, nsTArray<bool>& aBreakBefore)
+PropertyProvider::GetHyphenationBreaks(Range aRange,
+                                       nsTArray<HyphenType>& 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 == StyleHyphens::None)
   {
-    memset(aBreakBefore.Elements(), false, aRange.Length() * sizeof(bool));
+    memset(aBreakBefore.Elements(), static_cast<uint8_t>(HyphenType::None),
+           aRange.Length() * sizeof(HyphenType));
     return;
   }
 
   // Iterate through the original-string character runs
   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
@@ -3609,30 +3612,33 @@ PropertyProvider::GetHyphenationBreaks(R
     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() - aRange.start;
-      memset(aBreakBefore.Elements() + runOffsetInSubstring, false,
-             run.GetRunLength() * sizeof(bool));
+      memset(aBreakBefore.Elements() + runOffsetInSubstring,
+             static_cast<uint8_t>(HyphenType::None),
+             run.GetRunLength() * sizeof(HyphenType));
       // Don't allow hyphen breaks at the start of the line
-      aBreakBefore[runOffsetInSubstring] = allowHyphenBreakBeforeNextChar &&
+      aBreakBefore[runOffsetInSubstring] =
+          allowHyphenBreakBeforeNextChar &&
           (!(mFrame->GetStateBits() & TEXT_START_OF_LINE) ||
-           run.GetSkippedOffset() > mStart.GetSkippedOffset());
+           run.GetSkippedOffset() > mStart.GetSkippedOffset()) ?
+          HyphenType::Manual : HyphenType::None;
       allowHyphenBreakBeforeNextChar = false;
     }
   }
 
   if (mTextStyle->mHyphens == StyleHyphens::Auto) {
     for (uint32_t i = 0; i < aRange.Length(); ++i) {
       if (mTextRun->CanHyphenateBefore(aRange.start + i)) {
-        aBreakBefore[i] = true;
+        aBreakBefore[i] = HyphenType::Auto;
       }
     }
   }
 }
 
 void
 PropertyProvider::InitializeForDisplay(bool aTrimAfter)
 {
@@ -8365,17 +8371,17 @@ nsTextFrame::AddInlineMinISizeForFlow(ns
     if (start < flowEndInTextRun && textRun->CanBreakLineBefore(start)) {
       aData->OptionallyBreak();
     }
     aData->mCurrentLine += provider.GetFontMetrics()->EmHeight();
     aData->mTrailingWhitespace = 0;
     return;
   }
 
-  AutoTArray<bool,BIG_TEXT_NODE_SIZE> hyphBuffer;
+  AutoTArray<gfxTextRun::HyphenType, BIG_TEXT_NODE_SIZE> hyphBuffer;
   if (hyphenating &&
       hyphBuffer.AppendElements(flowEndInTextRun - start, fallible)) {
     provider.GetHyphenationBreaks(Range(start, flowEndInTextRun), hyphBuffer);
   }
 
   for (uint32_t i = start, wordStart = start; i <= flowEndInTextRun; ++i) {
     bool preformattedNewline = false;
     bool preformattedTab = false;
@@ -8383,17 +8389,18 @@ nsTextFrame::AddInlineMinISizeForFlow(ns
       // XXXldb Shouldn't we be including the newline as part of the
       // segment that it ends rather than part of the segment that it
       // starts?
       preformattedNewline = preformatNewlines && textRun->CharIsNewline(i);
       preformattedTab = preformatTabs && textRun->CharIsTab(i);
       if (!textRun->CanBreakLineBefore(i) &&
           !preformattedNewline &&
           !preformattedTab &&
-          (hyphBuffer.IsEmpty() || !hyphBuffer[i - start]))
+          (hyphBuffer.IsEmpty() ||
+           hyphBuffer[i - start] == gfxTextRun::HyphenType::None))
       {
         // we can't break here (and it's not the end of the flow)
         continue;
       }
     }
 
     if (i > wordStart) {
       nscoord width = NSToCoordCeilClamped(
@@ -8431,17 +8438,17 @@ nsTextFrame::AddInlineMinISizeForFlow(ns
       aData->mCurrentLine = nscoord(afterTab + spacing.mAfter);
       wordStart = i + 1;
     } else if (i < flowEndInTextRun ||
         (i == textRun->GetLength() &&
          (textRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK))) {
       if (preformattedNewline) {
         aData->ForceBreak();
       } else if (i < flowEndInTextRun && !hyphBuffer.IsEmpty() &&
-                 hyphBuffer[i - start]) {
+                 hyphBuffer[i - start] != gfxTextRun::HyphenType::None) {
         aData->OptionallyBreak(NSToCoordRound(provider.GetHyphenWidth()));
       } else {
         aData->OptionallyBreak();
       }
       wordStart = i;
     }
   }