Bug 374720. Minor gfx changes to support new textframe work. r=pavlov
authorroc+@cs.cmu.edu
Thu, 22 Mar 2007 16:07:18 -0700
changeset 6 dad02d3ebc7d9e5fdfed17234d31d10e3b1b55ec
parent 5 331cb67f2a3cb141465e0da88f8cd1ef36e85ffc
child 7 cd100ce4677919334ec2e3ffb57b444aabf81141
push idunknown
push userunknown
push dateunknown
reviewerspavlov
bugs374720
milestone1.9a3pre
Bug 374720. Minor gfx changes to support new textframe work. r=pavlov
gfx/thebes/public/gfxAtsuiFonts.h
gfx/thebes/public/gfxFont.h
gfx/thebes/public/gfxWindowsFonts.h
gfx/thebes/src/gfxAtsuiFonts.cpp
gfx/thebes/src/gfxFont.cpp
gfx/thebes/src/gfxPangoFonts.cpp
gfx/thebes/src/gfxWindowsFonts.cpp
--- a/gfx/thebes/public/gfxAtsuiFonts.h
+++ b/gfx/thebes/public/gfxAtsuiFonts.h
@@ -90,20 +90,18 @@ protected:
 };
 
 class THEBES_API gfxAtsuiFontGroup : public gfxFontGroup {
 public:
     gfxAtsuiFontGroup(const nsAString& families,
                       const gfxFontStyle *aStyle);
     virtual ~gfxAtsuiFontGroup();
 
-    virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) {
-        NS_ERROR("NOT IMPLEMENTED");
-        return nsnull;
-    }
+    virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
+
     virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
                                     Parameters* aParams);
     virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
                                     Parameters* aParams);
     // Here, aString is actually aLength + aHeaderChars*2 chars long; the first char
     // may be a LRO or RLO bidi control character to force setting the direction
     // for all characters, and if so the last character will be a PDF
     gfxTextRun *MakeTextRunInternal(const PRUnichar *aString, PRUint32 aLength,
--- a/gfx/thebes/public/gfxFont.h
+++ b/gfx/thebes/public/gfxFont.h
@@ -412,17 +412,17 @@ public:
  * any given cluster. (Line breaks specified inside clusters are ignored.)
  * 
  * gfxTextRuns don't need to remember their text ... often it's enough just to
  * convert text to glyphs and store glyphs plus some geometry data in packed
  * form. However sometimes gfxTextRuns will want to get the original text back
  * to handle some unusual situation. So gfxTextRuns have two modes: "not
  * remembering text" (initial state) and "remembering text". A call to
  * gfxTextRun::RememberText forces a transition from the former to latter state.
- * The text is never forgotten. A gfxTextRun call that receives a TextProvider
+ * The text is never forgotten. A gfxTextRun call that receives a PropertyProvider
  * object may call ForceRememberText to request a transition to "remembering text".
  * 
  * It is important that zero-length substrings are handled correctly. This will
  * be on the test!
  * 
  * gfxTextRun stores a list of zero or more glyphs for each character. For each
  * glyph we store the glyph ID, the advance, and possibly an xoffset and yoffset.
  * The idea is that a string is rendered by a loop that draws each glyph
@@ -461,63 +461,60 @@ public:
     // All PRUint32 aStart, PRUint32 aLength ranges below are restricted to
     // grapheme cluster boundaries! All offsets are in terms of the string
     // passed into MakeTextRun.
     
     // All coordinates are in layout/app units
 
     /**
      * This can be called to force gfxTextRun to remember the text used
-     * to create it and *never* call TextProvider::GetText again.
+     * to create it and *never* call PropertyProvider::GetText again.
      * 
      * Right now we don't implement these.
      */
     void RememberText(const PRUnichar *aText, PRUint32 aLength) {}
     void RememberText(const PRUint8 *aText, PRUint32 aLength) {}
 
     /**
      * 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
      */
-    PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
-                                  PRPackedBool *aBreakBefore);
-
-    /**
-     * This is provided so a textrun can (re)obtain the original text used to
-     * construct it, if necessary.
-     */
-    class TextProvider {
-    public:
-        /**
-         * Recover the text originally used to build the textrun. This should
-         * only be requested infrequently as it may be slow. If you need to
-         * call it a lot you should probably be saving the text in the text run
-         * itself. It just forces the textrun user to call RememberText on the
-         * text run. If you call this and RememberText doesn't get called,
-         * then something has failed and you should handle it.
-         */
-        virtual void ForceRememberText() = 0;
-    };
+    virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
+                                          PRPackedBool *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 TextProvider {
+    class PropertyProvider {
     public:
+        /**
+         * Recover the text originally used to build the textrun. This should
+         * only be requested infrequently as it may be slow. If you need to
+         * call it a lot you should probably be saving the text in the text run
+         * itself. It just forces the textrun user to call RememberText on the
+         * text run. If you call this and RememberText doesn't get called,
+         * then something has failed and you should handle it.
+         */
+        virtual void ForceRememberText() = 0;
+
         // Detect hyphenation break opportunities in the given range; breaks
         // not at cluster boundaries will be ignored.
         virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
                                           PRPackedBool *aBreakBefore) = 0;
 
         // Returns the extra width that will be consumed by a hyphen. This should
         // be constant for a given textrun.
         virtual gfxFloat GetHyphenWidth() = 0;
@@ -615,23 +612,27 @@ public:
      * This can change textrun geometry! The existence of a linebreak can affect
      * the advance width of the cluster before the break (when kerning) or the
      * geometry of one cluster before the break or any number of clusters
      * after the break. (The one-cluster-before-the-break limit is somewhat
      * arbitrary; if some scripts require breaking it, then we need to
      * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
      * it could affect the layout of frames before it...)
      * 
+     * 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.
      */
-    void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
-                       PRBool aLineBreakBefore, PRBool aLineBreakAfter,
-                       TextProvider *aProvider,
-                       gfxFloat *aAdvanceWidthDelta);
+    virtual PRBool SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
+                                 PRBool aLineBreakBefore, PRBool aLineBreakAfter,
+                                 PropertyProvider *aProvider,
+                                 gfxFloat *aAdvanceWidthDelta);
 
     /**
      * Finds the longest substring that will fit into the given width.
      * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
      * Guarantees the following:
      * -- 0 <= result <= aMaxLength
      * -- result is the maximal value of N such that either
      *       N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
@@ -862,16 +863,17 @@ public:
      * This should be called after creating a Unicode textrun.
      */
     void RecordSurrogates(const PRUnichar *aString);
     /**
      * We've found a run of text that should use a particular font. Call this
      * only during initialization when font substitution has been computed.
      */
     nsresult AddGlyphRun(gfxFont *aFont, PRUint32 aStartCharIndex);
+    void ResetGlyphRuns() { mGlyphRuns.Clear(); }
     // Call the following glyph-setters during initialization or during reshaping
     // only. It is OK to overwrite existing data for a character.
     /**
      * Set the glyph for a character. Also allows you to set low surrogates,
      * cluster and ligature continuations.
      */
     void SetCharacterGlyph(PRUint32 aCharIndex, CompressedGlyph aGlyph) {
         NS_ASSERTION(aCharIndex > 0 ||
@@ -883,29 +885,33 @@ public:
         if (mDetailedGlyphs) {
             mDetailedGlyphs[aCharIndex] = nsnull;
         }
     }
     /**
      * Set some detailed glyphs for a character. The data is copied from aGlyphs,
      * the caller retains ownership.
      */
-    void SetDetailedGlyphs(PRUint32 aCharIndex, DetailedGlyph *aGlyphs,
+    void SetDetailedGlyphs(PRUint32 aCharIndex, const DetailedGlyph *aGlyphs,
                            PRUint32 aNumGlyphs);
 
     // API for access to the raw glyph data, needed by gfxFont::Draw
     // and gfxFont::GetBoundingBox
     const CompressedGlyph *GetCharacterGlyphs() { return mCharacterGlyphs; }
     const DetailedGlyph *GetDetailedGlyphs(PRUint32 aCharIndex) {
         NS_ASSERTION(mDetailedGlyphs && mDetailedGlyphs[aCharIndex],
                      "Requested detailed glyphs when there aren't any, "
                      "I think I'll go and have a lie down...");
         return mDetailedGlyphs[aCharIndex];
     }
     PRUint32 CountMissingGlyphs();
+    const GlyphRun *GetGlyphRuns(PRUint32 *aNumGlyphRuns) {
+        *aNumGlyphRuns = mGlyphRuns.Length();
+        return mGlyphRuns.Elements();
+    }
 
 private:
     // **** general helpers **** 
 
     // Returns the index of the GlyphRun containing the given offset.
     // Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
     PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
     // Computes the x-advance for a given cluster starting at aClusterOffset. Does
--- a/gfx/thebes/public/gfxWindowsFonts.h
+++ b/gfx/thebes/public/gfxWindowsFonts.h
@@ -421,20 +421,18 @@ private:
  **********************************************************************/
 
 class THEBES_API gfxWindowsFontGroup : public gfxFontGroup {
 
 public:
     gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle);
     virtual ~gfxWindowsFontGroup();
 
-    virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) {
-        NS_ERROR("NOT IMPLEMENTED");
-        return nsnull;
-    }
+    virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
+
     virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
                                     Parameters* aParams);
     virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
                                     Parameters* aParams);
 
     const nsACString& GetGenericFamily() const {
         return mGenericFamily;
     }
--- a/gfx/thebes/src/gfxAtsuiFonts.cpp
+++ b/gfx/thebes/src/gfxAtsuiFonts.cpp
@@ -337,16 +337,22 @@ gfxAtsuiFontGroup::FindATSUFont(const ns
     return PR_TRUE;
 }
 
 gfxAtsuiFontGroup::~gfxAtsuiFontGroup()
 {
     ATSUDisposeFontFallbacks(mFallbacks);
 }
 
+gfxFontGroup *
+gfxAtsuiFontGroup::Copy(const gfxFontStyle *aStyle)
+{
+    return new gfxAtsuiFontGroup(mFamilies, aStyle);
+}
+
 static void
 SetupClusterBoundaries(gfxTextRun *aTextRun, const PRUnichar *aString, PRUint32 aLength)
 {
     TextBreakLocatorRef locator;
     OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakClusterMask,
                                                &locator);
     if (status != noErr)
         return;
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -157,18 +157,19 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUi
 
 gfxFont::RunMetrics
 gfxFont::Measure(gfxTextRun *aTextRun,
                  PRUint32 aStart, PRUint32 aEnd,
                  PRBool aTightBoundingBox,
                  Spacing *aSpacing)
 {
     // XXX temporary code, does not handle glyphs outside the font-box
-    NS_ASSERTION(!(aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX),
-                 "Glyph extents not yet supported");
+    // XXX comment out the assertion for now since it fires too much
+    // NS_ASSERTION(!(aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX),
+    //              "Glyph extents not yet supported");
     PRInt32 advance = 0;
     PRUint32 i;
     const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs();
     PRUint32 clusterCount = 0;
     for (i = aStart; i < aEnd; ++i) {
         gfxTextRun::CompressedGlyph g = charGlyphs[i];
         if (g.IsClusterStart()) {
             ++clusterCount;
@@ -1239,28 +1240,28 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aSt
                 ++details;
             }
         }
     }
 
     return result;
 }
 
-
-void
+PRBool
 gfxTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
                           PRBool aLineBreakBefore, PRBool aLineBreakAfter,
-                          TextProvider *aProvider,
+                          PropertyProvider *aProvider,
                           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;
     }
+    return PR_FALSE;
 }
 
 PRUint32
 gfxTextRun::FindFirstGlyphRunContaining(PRUint32 aOffset)
 {
     NS_ASSERTION(aOffset <= mCharacterCount, "Bad offset looking for glyphrun");
     if (aOffset == mCharacterCount)
         return mGlyphRuns.Length();
@@ -1302,17 +1303,17 @@ gfxTextRun::CountMissingGlyphs()
         if (mCharacterGlyphs[i].IsMissing()) {
             ++count;
         }
     }
     return count;
 }
 
 void
-gfxTextRun::SetDetailedGlyphs(PRUint32 aIndex, DetailedGlyph *aGlyphs,
+gfxTextRun::SetDetailedGlyphs(PRUint32 aIndex, const DetailedGlyph *aGlyphs,
                               PRUint32 aCount)
 {
     NS_ASSERTION(aCount > 0, "Can't set zero detailed glyphs");
     NS_ASSERTION(aGlyphs[aCount - 1].mIsLastGlyph, "Failed to set last glyph flag");
 
     if (!mCharacterGlyphs)
         return;
 
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -778,17 +778,17 @@ gfxPangoFont::Measure(gfxTextRun *aTextR
     PRUint32 clusterCount = aEnd - aStart;
     PRBool isRTL = aTextRun->IsRightToLeft();
 
     PRUint32 i;
     for (i = aStart; i < aEnd; ++i) {
         PRUint32 leftSpacePango = 0;
         PRUint32 rightSpacePango = 0;
         if (aSpacing) {
-            gfxTextRun::PropertyProvider::Spacing *space = &aSpacing[i];
+            gfxTextRun::PropertyProvider::Spacing *space = &aSpacing[i - aStart];
             leftSpacePango =
                 NS_lround((isRTL ? space->mAfter : space->mBefore)*appUnitsToPango);
             rightSpacePango =
                 NS_lround((isRTL ? space->mBefore : space->mAfter)*appUnitsToPango);
         }
         const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
         if (glyphData->IsSimpleGlyph()) {
             PangoGlyphInfo *glyphInfo = glyphBuffer.AppendElement();
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -531,16 +531,22 @@ gfxWindowsFontGroup::gfxWindowsFontGroup
         MakeFont(defaultFont, mGenericFamily, this);
     }
 }
 
 gfxWindowsFontGroup::~gfxWindowsFontGroup()
 {
 }
 
+gfxFontGroup *
+gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
+{
+    return new gfxWindowsFontGroup(mFamilies, aStyle);
+}
+
 gfxTextRun *
 gfxWindowsFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
                                  Parameters *aParams)
 {
     NS_ASSERTION(!(aParams->mFlags & TEXT_NEED_BOUNDING_BOX),
                  "Glyph extents not yet supported");
 
     gfxTextRun *textRun = new gfxTextRun(aParams, aLength);