michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef MOZILLA_SVGTEXTFRAME_H michael@0: #define MOZILLA_SVGTEXTFRAME_H michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/RefPtr.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: #include "gfxMatrix.h" michael@0: #include "gfxRect.h" michael@0: #include "gfxSVGGlyphs.h" michael@0: #include "nsIContent.h" michael@0: #include "nsStubMutationObserver.h" michael@0: #include "nsSVGPaintServerFrame.h" michael@0: michael@0: class nsDisplaySVGText; michael@0: class nsRenderingContext; michael@0: class SVGTextFrame; michael@0: class nsTextFrame; michael@0: michael@0: typedef nsSVGDisplayContainerFrame SVGTextFrameBase; michael@0: michael@0: namespace mozilla { michael@0: michael@0: class CharIterator; michael@0: class nsISVGPoint; michael@0: class TextFrameIterator; michael@0: class TextNodeCorrespondenceRecorder; michael@0: struct TextRenderedRun; michael@0: class TextRenderedRunIterator; michael@0: michael@0: namespace dom { michael@0: class SVGIRect; michael@0: } michael@0: michael@0: /** michael@0: * Information about the positioning for a single character in an SVG michael@0: * element. michael@0: * michael@0: * During SVG text layout, we use infinity values to represent positions and michael@0: * rotations that are not explicitly specified with x/y/rotate attributes. michael@0: */ michael@0: struct CharPosition michael@0: { michael@0: CharPosition() michael@0: : mAngle(0), michael@0: mHidden(false), michael@0: mUnaddressable(false), michael@0: mClusterOrLigatureGroupMiddle(false), michael@0: mRunBoundary(false), michael@0: mStartOfChunk(false) michael@0: { michael@0: } michael@0: michael@0: CharPosition(gfxPoint aPosition, double aAngle) michael@0: : mPosition(aPosition), michael@0: mAngle(aAngle), michael@0: mHidden(false), michael@0: mUnaddressable(false), michael@0: mClusterOrLigatureGroupMiddle(false), michael@0: mRunBoundary(false), michael@0: mStartOfChunk(false) michael@0: { michael@0: } michael@0: michael@0: static CharPosition Unspecified(bool aUnaddressable) michael@0: { michael@0: CharPosition cp(UnspecifiedPoint(), UnspecifiedAngle()); michael@0: cp.mUnaddressable = aUnaddressable; michael@0: return cp; michael@0: } michael@0: michael@0: bool IsAngleSpecified() const michael@0: { michael@0: return mAngle != UnspecifiedAngle(); michael@0: } michael@0: michael@0: bool IsXSpecified() const michael@0: { michael@0: return mPosition.x != UnspecifiedCoord(); michael@0: } michael@0: michael@0: bool IsYSpecified() const michael@0: { michael@0: return mPosition.y != UnspecifiedCoord(); michael@0: } michael@0: michael@0: gfxPoint mPosition; michael@0: double mAngle; michael@0: michael@0: // not displayed due to falling off the end of a michael@0: bool mHidden; michael@0: michael@0: // skipped in positioning attributes due to being collapsed-away white space michael@0: bool mUnaddressable; michael@0: michael@0: // a preceding character is what positioning attributes address michael@0: bool mClusterOrLigatureGroupMiddle; michael@0: michael@0: // rendering is split here since an explicit position or rotation was given michael@0: bool mRunBoundary; michael@0: michael@0: // an anchored chunk begins here michael@0: bool mStartOfChunk; michael@0: michael@0: private: michael@0: static gfxFloat UnspecifiedCoord() michael@0: { michael@0: return std::numeric_limits::infinity(); michael@0: } michael@0: michael@0: static double UnspecifiedAngle() michael@0: { michael@0: return std::numeric_limits::infinity(); michael@0: } michael@0: michael@0: static gfxPoint UnspecifiedPoint() michael@0: { michael@0: return gfxPoint(UnspecifiedCoord(), UnspecifiedCoord()); michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * A runnable to mark glyph positions as needing to be recomputed michael@0: * and to invalid the bounds of the SVGTextFrame frame. michael@0: */ michael@0: class GlyphMetricsUpdater : public nsRunnable { michael@0: public: michael@0: NS_DECL_NSIRUNNABLE michael@0: GlyphMetricsUpdater(SVGTextFrame* aFrame) : mFrame(aFrame) { } michael@0: static void Run(SVGTextFrame* aFrame); michael@0: void Revoke() { mFrame = nullptr; } michael@0: private: michael@0: SVGTextFrame* mFrame; michael@0: }; michael@0: michael@0: // Slightly horrible callback for deferring application of opacity michael@0: struct SVGTextContextPaint : public gfxTextContextPaint { michael@0: already_AddRefed GetFillPattern(float aOpacity, michael@0: const gfxMatrix& aCTM) MOZ_OVERRIDE; michael@0: already_AddRefed GetStrokePattern(float aOpacity, michael@0: const gfxMatrix& aCTM) MOZ_OVERRIDE; michael@0: michael@0: void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; } michael@0: float GetFillOpacity() MOZ_OVERRIDE { return mFillOpacity; } michael@0: michael@0: void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; } michael@0: float GetStrokeOpacity() MOZ_OVERRIDE { return mStrokeOpacity; } michael@0: michael@0: struct Paint { michael@0: Paint() : mPaintType(eStyleSVGPaintType_None) {} michael@0: michael@0: void SetPaintServer(nsIFrame *aFrame, const gfxMatrix& aContextMatrix, michael@0: nsSVGPaintServerFrame *aPaintServerFrame) { michael@0: mPaintType = eStyleSVGPaintType_Server; michael@0: mPaintDefinition.mPaintServerFrame = aPaintServerFrame; michael@0: mFrame = aFrame; michael@0: mContextMatrix = aContextMatrix; michael@0: } michael@0: michael@0: void SetColor(const nscolor &aColor) { michael@0: mPaintType = eStyleSVGPaintType_Color; michael@0: mPaintDefinition.mColor = aColor; michael@0: } michael@0: michael@0: void SetContextPaint(gfxTextContextPaint *aContextPaint, michael@0: nsStyleSVGPaintType aPaintType) { michael@0: NS_ASSERTION(aPaintType == eStyleSVGPaintType_ContextFill || michael@0: aPaintType == eStyleSVGPaintType_ContextStroke, michael@0: "Invalid context paint type"); michael@0: mPaintType = aPaintType; michael@0: mPaintDefinition.mContextPaint = aContextPaint; michael@0: } michael@0: michael@0: union { michael@0: nsSVGPaintServerFrame *mPaintServerFrame; michael@0: gfxTextContextPaint *mContextPaint; michael@0: nscolor mColor; michael@0: } mPaintDefinition; michael@0: michael@0: nsIFrame *mFrame; michael@0: // CTM defining the user space for the pattern we will use. michael@0: gfxMatrix mContextMatrix; michael@0: nsStyleSVGPaintType mPaintType; michael@0: michael@0: // Device-space-to-pattern-space michael@0: gfxMatrix mPatternMatrix; michael@0: nsRefPtrHashtable mPatternCache; michael@0: michael@0: already_AddRefed GetPattern(float aOpacity, michael@0: nsStyleSVGPaint nsStyleSVG::*aFillOrStroke, michael@0: const gfxMatrix& aCTM); michael@0: }; michael@0: michael@0: Paint mFillPaint; michael@0: Paint mStrokePaint; michael@0: michael@0: float mFillOpacity; michael@0: float mStrokeOpacity; michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: /** michael@0: * Frame class for SVG elements, used when the michael@0: * layout.svg.css-text.enabled is true. michael@0: * michael@0: * An SVGTextFrame manages SVG text layout, painting and interaction for michael@0: * all descendent text content elements. The frame tree will look like this: michael@0: * michael@0: * SVGTextFrame -- for michael@0: * michael@0: * ns{Block,Inline,Text}Frames -- for text nodes, s, s, etc. michael@0: * michael@0: * SVG text layout is done by: michael@0: * michael@0: * 1. Reflowing the anonymous block frame. michael@0: * 2. Inspecting the (app unit) positions of the glyph for each character in michael@0: * the nsTextFrames underneath the anonymous block frame. michael@0: * 3. Determining the (user unit) positions for each character in the michael@0: * using the x/y/dx/dy/rotate attributes on all the text content elements, michael@0: * and using the step 2 results to fill in any gaps. michael@0: * 4. Applying any other SVG specific text layout (anchoring and text paths) michael@0: * to the positions computed in step 3. michael@0: * michael@0: * Rendering of the text is done by splitting up each nsTextFrame into ranges michael@0: * that can be contiguously painted. (For example abcd michael@0: * would have two contiguous ranges: one for the "a" and one for the "bcd".) michael@0: * Each range is called a "text rendered run", represented by a TextRenderedRun michael@0: * object. The TextRenderedRunIterator class performs that splitting and michael@0: * returns a TextRenderedRun for each bit of text to be painted separately. michael@0: * michael@0: * Each rendered run is painted by calling nsTextFrame::PaintText. If the text michael@0: * formatting is simple enough (solid fill, no stroking, etc.), PaintText will michael@0: * itself do the painting. Otherwise, a DrawPathCallback is passed to michael@0: * PaintText so that we can fill the text geometry with SVG paint servers. michael@0: */ michael@0: class SVGTextFrame : public SVGTextFrameBase michael@0: { michael@0: friend nsIFrame* michael@0: NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); michael@0: michael@0: friend class mozilla::CharIterator; michael@0: friend class mozilla::GlyphMetricsUpdater; michael@0: friend class mozilla::TextFrameIterator; michael@0: friend class mozilla::TextNodeCorrespondenceRecorder; michael@0: friend struct mozilla::TextRenderedRun; michael@0: friend class mozilla::TextRenderedRunIterator; michael@0: friend class MutationObserver; michael@0: friend class nsDisplaySVGText; michael@0: michael@0: typedef mozilla::gfx::Path Path; michael@0: typedef mozilla::SVGTextContextPaint SVGTextContextPaint; michael@0: michael@0: protected: michael@0: SVGTextFrame(nsStyleContext* aContext) michael@0: : SVGTextFrameBase(aContext), michael@0: mFontSizeScaleFactor(1.0f), michael@0: mLastContextScale(1.0f), michael@0: mLengthAdjustScaleFactor(1.0f) michael@0: { michael@0: AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY); michael@0: } michael@0: michael@0: public: michael@0: NS_DECL_QUERYFRAME_TARGET(SVGTextFrame) michael@0: NS_DECL_QUERYFRAME michael@0: NS_DECL_FRAMEARENA_HELPERS michael@0: michael@0: // nsIFrame: michael@0: virtual void Init(nsIContent* aContent, michael@0: nsIFrame* aParent, michael@0: nsIFrame* aPrevInFlow) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult AttributeChanged(int32_t aNamespaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType) MOZ_OVERRIDE; michael@0: michael@0: virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE michael@0: { michael@0: return GetFirstPrincipalChild()->GetContentInsertionFrame(); michael@0: } michael@0: michael@0: virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Get the "type" of the frame michael@0: * michael@0: * @see nsGkAtoms::svgTextFrame michael@0: */ michael@0: virtual nsIAtom* GetType() const MOZ_OVERRIDE; michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE michael@0: { michael@0: return MakeFrameName(NS_LITERAL_STRING("SVGText"), aResult); michael@0: } michael@0: #endif michael@0: michael@0: virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Finds the nsTextFrame for the closest rendered run to the specified point. michael@0: */ michael@0: virtual void FindCloserFrameForSelection(nsPoint aPoint, michael@0: FrameWithDistance* aCurrentBestFrame) MOZ_OVERRIDE; michael@0: michael@0: michael@0: michael@0: // nsISVGChildFrame interface: michael@0: virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE; michael@0: virtual nsresult PaintSVG(nsRenderingContext* aContext, michael@0: const nsIntRect* aDirtyRect, michael@0: nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE; michael@0: virtual nsIFrame* GetFrameForPoint(const nsPoint& aPoint) MOZ_OVERRIDE; michael@0: virtual void ReflowSVG() MOZ_OVERRIDE; michael@0: virtual nsRect GetCoveredRegion() MOZ_OVERRIDE; michael@0: virtual SVGBBox GetBBoxContribution(const Matrix& aToBBoxUserspace, michael@0: uint32_t aFlags) MOZ_OVERRIDE; michael@0: michael@0: // nsSVGContainerFrame methods: michael@0: virtual gfxMatrix GetCanvasTM(uint32_t aFor, michael@0: nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE; michael@0: michael@0: // SVG DOM text methods: michael@0: uint32_t GetNumberOfChars(nsIContent* aContent); michael@0: float GetComputedTextLength(nsIContent* aContent); michael@0: nsresult SelectSubString(nsIContent* aContent, uint32_t charnum, uint32_t nchars); michael@0: nsresult GetSubStringLength(nsIContent* aContent, uint32_t charnum, michael@0: uint32_t nchars, float* aResult); michael@0: int32_t GetCharNumAtPosition(nsIContent* aContent, mozilla::nsISVGPoint* point); michael@0: michael@0: nsresult GetStartPositionOfChar(nsIContent* aContent, uint32_t aCharNum, michael@0: mozilla::nsISVGPoint** aResult); michael@0: nsresult GetEndPositionOfChar(nsIContent* aContent, uint32_t aCharNum, michael@0: mozilla::nsISVGPoint** aResult); michael@0: nsresult GetExtentOfChar(nsIContent* aContent, uint32_t aCharNum, michael@0: mozilla::dom::SVGIRect** aResult); michael@0: nsresult GetRotationOfChar(nsIContent* aContent, uint32_t aCharNum, michael@0: float* aResult); michael@0: michael@0: // SVGTextFrame methods: michael@0: michael@0: /** michael@0: * Schedules mPositions to be recomputed and the covered region to be michael@0: * updated. michael@0: */ michael@0: void NotifyGlyphMetricsChange(); michael@0: michael@0: /** michael@0: * Calls ScheduleReflowSVGNonDisplayText if this is a non-display frame, michael@0: * and nsSVGUtils::ScheduleReflowSVG otherwise. michael@0: */ michael@0: void ScheduleReflowSVG(); michael@0: michael@0: /** michael@0: * Reflows the anonymous block frame of this non-display SVGTextFrame. michael@0: * michael@0: * When we are under nsSVGDisplayContainerFrame::ReflowSVG, we need to michael@0: * reflow any SVGTextFrame frames in the subtree in case they are michael@0: * being observed (by being for example in a ) and the change michael@0: * that caused the reflow would not already have caused a reflow. michael@0: * michael@0: * Note that displayed SVGTextFrames are reflowed as needed, when PaintSVG michael@0: * is called or some SVG DOM method is called on the element. michael@0: */ michael@0: void ReflowSVGNonDisplayText(); michael@0: michael@0: /** michael@0: * This is a function that behaves similarly to nsSVGUtils::ScheduleReflowSVG, michael@0: * but which will skip over any ancestor non-display container frames on the michael@0: * way to the nsSVGOuterSVGFrame. It exists for the situation where a michael@0: * non-display element has changed and needs to ensure ReflowSVG will michael@0: * be called on its closest display container frame, so that michael@0: * nsSVGDisplayContainerFrame::ReflowSVG will call ReflowSVGNonDisplayText on michael@0: * it. michael@0: * michael@0: * The only case where we have to do this is in response to a style change on michael@0: * a non-display ; the only caller of ScheduleReflowSVGNonDisplayText michael@0: * currently is SVGTextFrame::DidSetStyleContext. michael@0: */ michael@0: void ScheduleReflowSVGNonDisplayText(); michael@0: michael@0: /** michael@0: * Updates the mFontSizeScaleFactor value by looking at the range of michael@0: * font-sizes used within the . michael@0: * michael@0: * @return Whether mFontSizeScaleFactor changed. michael@0: */ michael@0: bool UpdateFontSizeScaleFactor(); michael@0: michael@0: double GetFontSizeScaleFactor() const; michael@0: michael@0: /** michael@0: * Takes a point from the element's user space and michael@0: * converts it to the appropriate frame user space of aChildFrame, michael@0: * according to which rendered run the point hits. michael@0: */ michael@0: gfxPoint TransformFramePointToTextChild(const gfxPoint& aPoint, michael@0: nsIFrame* aChildFrame); michael@0: michael@0: /** michael@0: * Takes a rectangle, aRect, in the element's user space, and michael@0: * returns a rectangle in aChildFrame's frame user space that michael@0: * covers intersections of aRect with each rendered run for text frames michael@0: * within aChildFrame. michael@0: */ michael@0: gfxRect TransformFrameRectToTextChild(const gfxRect& aRect, michael@0: nsIFrame* aChildFrame); michael@0: michael@0: /** michael@0: * Takes an app unit rectangle in the coordinate space of a given descendant michael@0: * frame of this frame, and returns a rectangle in the element's user michael@0: * space that covers all parts of rendered runs that intersect with the michael@0: * rectangle. michael@0: */ michael@0: gfxRect TransformFrameRectFromTextChild(const nsRect& aRect, michael@0: nsIFrame* aChildFrame); michael@0: michael@0: private: michael@0: /** michael@0: * Mutation observer used to watch for text positioning attribute changes michael@0: * on descendent text content elements (like s). michael@0: */ michael@0: class MutationObserver : public nsStubMutationObserver { michael@0: public: michael@0: MutationObserver() michael@0: : mFrame(nullptr) michael@0: { michael@0: } michael@0: michael@0: void StartObserving(SVGTextFrame* aFrame) michael@0: { michael@0: NS_ASSERTION(!mFrame, "should not be observing yet!"); michael@0: mFrame = aFrame; michael@0: aFrame->GetContent()->AddMutationObserver(this); michael@0: } michael@0: michael@0: virtual ~MutationObserver() michael@0: { michael@0: if (mFrame) { michael@0: mFrame->GetContent()->RemoveMutationObserver(this); michael@0: } michael@0: } michael@0: michael@0: // nsISupports michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsIMutationObserver michael@0: NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED michael@0: NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED michael@0: NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED michael@0: NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED michael@0: NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED michael@0: michael@0: private: michael@0: SVGTextFrame* mFrame; michael@0: }; michael@0: michael@0: /** michael@0: * Reflows the anonymous block child if it is dirty or has dirty michael@0: * children, or if the SVGTextFrame itself is dirty. michael@0: */ michael@0: void MaybeReflowAnonymousBlockChild(); michael@0: michael@0: /** michael@0: * Performs the actual work of reflowing the anonymous block child. michael@0: */ michael@0: void DoReflow(); michael@0: michael@0: /** michael@0: * Recomputes mPositions by calling DoGlyphPositioning if this information michael@0: * is out of date. michael@0: */ michael@0: void UpdateGlyphPositioning(); michael@0: michael@0: /** michael@0: * Populates mPositions with positioning information for each character michael@0: * within the . michael@0: */ michael@0: void DoGlyphPositioning(); michael@0: michael@0: /** michael@0: * Converts the specified index into mPositions to an addressable michael@0: * character index (as can be used with the SVG DOM text methods) michael@0: * relative to the specified text child content element. michael@0: * michael@0: * @param aIndex The global character index. michael@0: * @param aContent The descendant text child content element that michael@0: * the returned addressable index will be relative to; null michael@0: * means the same as the element. michael@0: * @return The addressable index, or -1 if the index cannot be michael@0: * represented as an addressable index relative to aContent. michael@0: */ michael@0: int32_t michael@0: ConvertTextElementCharIndexToAddressableIndex(int32_t aIndex, michael@0: nsIContent* aContent); michael@0: michael@0: /** michael@0: * Recursive helper for ResolvePositions below. michael@0: * michael@0: * @param aContent The current node. michael@0: * @param aIndex The current character index. michael@0: * @param aInTextPath Whether we are currently under a element. michael@0: * @param aForceStartOfChunk Whether the next character we find should start a michael@0: * new anchored chunk. michael@0: * @return The character index we got up to. michael@0: */ michael@0: uint32_t ResolvePositions(nsIContent* aContent, uint32_t aIndex, michael@0: bool aInTextPath, bool& aForceStartOfChunk, michael@0: nsTArray& aDeltas); michael@0: michael@0: /** michael@0: * Initializes mPositions with character position information based on michael@0: * x/y/rotate attributes, leaving unspecified values in the array if a position michael@0: * was not given for that character. Also fills aDeltas with values based on michael@0: * dx/dy attributes. michael@0: * michael@0: * @param aRunPerGlyph Whether mPositions should record that a new run begins michael@0: * at each glyph. michael@0: * @return True if we recorded any positions. michael@0: */ michael@0: bool ResolvePositions(nsTArray& aDeltas, bool aRunPerGlyph); michael@0: michael@0: /** michael@0: * Determines the position, in app units, of each character in the as michael@0: * laid out by reflow, and appends them to aPositions. Any characters that michael@0: * are undisplayed or trimmed away just get the last position. michael@0: */ michael@0: void DetermineCharPositions(nsTArray& aPositions); michael@0: michael@0: /** michael@0: * Sets mStartOfChunk to true for each character in mPositions that starts a michael@0: * line of text. michael@0: */ michael@0: void AdjustChunksForLineBreaks(); michael@0: michael@0: /** michael@0: * Adjusts recorded character positions in mPositions to account for glyph michael@0: * boundaries. Four things are done: michael@0: * michael@0: * 1. mClusterOrLigatureGroupMiddle is set to true for all such characters. michael@0: * michael@0: * 2. Any run and anchored chunk boundaries that begin in the middle of a michael@0: * cluster/ligature group get moved to the start of the next michael@0: * cluster/ligature group. michael@0: * michael@0: * 3. The position of any character in the middle of a cluster/ligature michael@0: * group is updated to take into account partial ligatures and any michael@0: * rotation the glyph as a whole has. (The values that come out of michael@0: * DetermineCharPositions which then get written into mPositions in michael@0: * ResolvePositions store the same position value for each part of the michael@0: * ligature.) michael@0: * michael@0: * 4. The rotation of any character in the middle of a cluster/ligature michael@0: * group is set to the rotation of the first character. michael@0: */ michael@0: void AdjustPositionsForClusters(); michael@0: michael@0: /** michael@0: * Updates the character positions stored in mPositions to account for michael@0: * text anchoring. michael@0: */ michael@0: void DoAnchoring(); michael@0: michael@0: /** michael@0: * Updates character positions in mPositions for those characters inside a michael@0: * . michael@0: */ michael@0: void DoTextPathLayout(); michael@0: michael@0: /** michael@0: * Returns whether we need to render the text using michael@0: * nsTextFrame::DrawPathCallbacks rather than directly painting michael@0: * the text frames. michael@0: * michael@0: * @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text michael@0: * should be painted. michael@0: */ michael@0: bool ShouldRenderAsPath(nsRenderingContext* aContext, nsTextFrame* aFrame, michael@0: bool& aShouldPaintSVGGlyphs); michael@0: michael@0: // Methods to get information for a frame. michael@0: nsIFrame* GetTextPathPathFrame(nsIFrame* aTextPathFrame); michael@0: mozilla::TemporaryRef GetTextPath(nsIFrame* aTextPathFrame); michael@0: gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame); michael@0: gfxFloat GetStartOffset(nsIFrame* aTextPathFrame); michael@0: michael@0: DrawMode SetupCairoState(gfxContext* aContext, michael@0: nsIFrame* aFrame, michael@0: gfxTextContextPaint* aOuterContextPaint, michael@0: gfxTextContextPaint** aThisContextPaint); michael@0: michael@0: /** michael@0: * Sets up the stroke style for |aFrame| in |aContext| and stores stroke michael@0: * pattern information in |aThisContextPaint|. michael@0: */ michael@0: bool SetupCairoStroke(gfxContext* aContext, michael@0: nsIFrame* aFrame, michael@0: gfxTextContextPaint* aOuterContextPaint, michael@0: SVGTextContextPaint* aThisContextPaint); michael@0: michael@0: /** michael@0: * Sets up the fill style for |aFrame| in |aContext| and stores fill pattern michael@0: * information in |aThisContextPaint|. michael@0: */ michael@0: bool SetupCairoFill(gfxContext* aContext, michael@0: nsIFrame* aFrame, michael@0: gfxTextContextPaint* aOuterContextPaint, michael@0: SVGTextContextPaint* aThisContextPaint); michael@0: michael@0: /** michael@0: * Stores in |aTargetPaint| information on how to reconstruct the current michael@0: * fill or stroke pattern. Will also set the paint opacity to transparent if michael@0: * the paint is set to "none". michael@0: * @param aOuterContextPaint pattern information from the outer text context michael@0: * @param aTargetPaint where to store the current pattern information michael@0: * @param aFillOrStroke member pointer to the paint we are setting up michael@0: * @param aProperty the frame property descriptor of the fill or stroke paint michael@0: * server frame michael@0: */ michael@0: void SetupInheritablePaint(gfxContext* aContext, michael@0: nsIFrame* aFrame, michael@0: float& aOpacity, michael@0: gfxTextContextPaint* aOuterContextPaint, michael@0: SVGTextContextPaint::Paint& aTargetPaint, michael@0: nsStyleSVGPaint nsStyleSVG::*aFillOrStroke, michael@0: const FramePropertyDescriptor* aProperty); michael@0: michael@0: /** michael@0: * The MutationObserver we have registered for the element subtree. michael@0: */ michael@0: MutationObserver mMutationObserver; michael@0: michael@0: /** michael@0: * Cached canvasTM value. michael@0: */ michael@0: nsAutoPtr mCanvasTM; michael@0: michael@0: /** michael@0: * The number of characters in the DOM after the final nsTextFrame. For michael@0: * example, with michael@0: * michael@0: * abcdef michael@0: * michael@0: * mTrailingUndisplayedCharacters would be 2. michael@0: */ michael@0: uint32_t mTrailingUndisplayedCharacters; michael@0: michael@0: /** michael@0: * Computed position information for each DOM character within the . michael@0: */ michael@0: nsTArray mPositions; michael@0: michael@0: /** michael@0: * mFontSizeScaleFactor is used to cause the nsTextFrames to create text michael@0: * runs with a font size different from the actual font-size property value. michael@0: * This is used so that, for example with: michael@0: * michael@0: * michael@0: * michael@0: * abc michael@0: * michael@0: * michael@0: * michael@0: * a font size of 20 would be used. It's preferable to use a font size that michael@0: * is identical or close to the size that the text will appear on the screen, michael@0: * because at very small or large font sizes, text metrics will be computed michael@0: * differently due to the limited precision that text runs have. michael@0: * michael@0: * mFontSizeScaleFactor is the amount the actual font-size property value michael@0: * should be multiplied by to cause the text run font size to (a) be within a michael@0: * "reasonable" range, and (b) be close to the actual size to be painted on michael@0: * screen. (The "reasonable" range as determined by some #defines in michael@0: * SVGTextFrame.cpp is 8..200.) michael@0: */ michael@0: float mFontSizeScaleFactor; michael@0: michael@0: /** michael@0: * The scale of the context that we last used to compute mFontSizeScaleFactor. michael@0: * We record this so that we can tell when our scale transform has changed michael@0: * enough to warrant reflowing the text. michael@0: */ michael@0: float mLastContextScale; michael@0: michael@0: /** michael@0: * The amount that we need to scale each rendered run to account for michael@0: * lengthAdjust="spacingAndGlyphs". michael@0: */ michael@0: float mLengthAdjustScaleFactor; michael@0: }; michael@0: michael@0: #endif