1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/svg/SVGTextFrame.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,698 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef MOZILLA_SVGTEXTFRAME_H 1.10 +#define MOZILLA_SVGTEXTFRAME_H 1.11 + 1.12 +#include "mozilla/Attributes.h" 1.13 +#include "mozilla/RefPtr.h" 1.14 +#include "mozilla/gfx/2D.h" 1.15 +#include "gfxMatrix.h" 1.16 +#include "gfxRect.h" 1.17 +#include "gfxSVGGlyphs.h" 1.18 +#include "nsIContent.h" 1.19 +#include "nsStubMutationObserver.h" 1.20 +#include "nsSVGPaintServerFrame.h" 1.21 + 1.22 +class nsDisplaySVGText; 1.23 +class nsRenderingContext; 1.24 +class SVGTextFrame; 1.25 +class nsTextFrame; 1.26 + 1.27 +typedef nsSVGDisplayContainerFrame SVGTextFrameBase; 1.28 + 1.29 +namespace mozilla { 1.30 + 1.31 +class CharIterator; 1.32 +class nsISVGPoint; 1.33 +class TextFrameIterator; 1.34 +class TextNodeCorrespondenceRecorder; 1.35 +struct TextRenderedRun; 1.36 +class TextRenderedRunIterator; 1.37 + 1.38 +namespace dom { 1.39 +class SVGIRect; 1.40 +} 1.41 + 1.42 +/** 1.43 + * Information about the positioning for a single character in an SVG <text> 1.44 + * element. 1.45 + * 1.46 + * During SVG text layout, we use infinity values to represent positions and 1.47 + * rotations that are not explicitly specified with x/y/rotate attributes. 1.48 + */ 1.49 +struct CharPosition 1.50 +{ 1.51 + CharPosition() 1.52 + : mAngle(0), 1.53 + mHidden(false), 1.54 + mUnaddressable(false), 1.55 + mClusterOrLigatureGroupMiddle(false), 1.56 + mRunBoundary(false), 1.57 + mStartOfChunk(false) 1.58 + { 1.59 + } 1.60 + 1.61 + CharPosition(gfxPoint aPosition, double aAngle) 1.62 + : mPosition(aPosition), 1.63 + mAngle(aAngle), 1.64 + mHidden(false), 1.65 + mUnaddressable(false), 1.66 + mClusterOrLigatureGroupMiddle(false), 1.67 + mRunBoundary(false), 1.68 + mStartOfChunk(false) 1.69 + { 1.70 + } 1.71 + 1.72 + static CharPosition Unspecified(bool aUnaddressable) 1.73 + { 1.74 + CharPosition cp(UnspecifiedPoint(), UnspecifiedAngle()); 1.75 + cp.mUnaddressable = aUnaddressable; 1.76 + return cp; 1.77 + } 1.78 + 1.79 + bool IsAngleSpecified() const 1.80 + { 1.81 + return mAngle != UnspecifiedAngle(); 1.82 + } 1.83 + 1.84 + bool IsXSpecified() const 1.85 + { 1.86 + return mPosition.x != UnspecifiedCoord(); 1.87 + } 1.88 + 1.89 + bool IsYSpecified() const 1.90 + { 1.91 + return mPosition.y != UnspecifiedCoord(); 1.92 + } 1.93 + 1.94 + gfxPoint mPosition; 1.95 + double mAngle; 1.96 + 1.97 + // not displayed due to falling off the end of a <textPath> 1.98 + bool mHidden; 1.99 + 1.100 + // skipped in positioning attributes due to being collapsed-away white space 1.101 + bool mUnaddressable; 1.102 + 1.103 + // a preceding character is what positioning attributes address 1.104 + bool mClusterOrLigatureGroupMiddle; 1.105 + 1.106 + // rendering is split here since an explicit position or rotation was given 1.107 + bool mRunBoundary; 1.108 + 1.109 + // an anchored chunk begins here 1.110 + bool mStartOfChunk; 1.111 + 1.112 +private: 1.113 + static gfxFloat UnspecifiedCoord() 1.114 + { 1.115 + return std::numeric_limits<gfxFloat>::infinity(); 1.116 + } 1.117 + 1.118 + static double UnspecifiedAngle() 1.119 + { 1.120 + return std::numeric_limits<double>::infinity(); 1.121 + } 1.122 + 1.123 + static gfxPoint UnspecifiedPoint() 1.124 + { 1.125 + return gfxPoint(UnspecifiedCoord(), UnspecifiedCoord()); 1.126 + } 1.127 +}; 1.128 + 1.129 +/** 1.130 + * A runnable to mark glyph positions as needing to be recomputed 1.131 + * and to invalid the bounds of the SVGTextFrame frame. 1.132 + */ 1.133 +class GlyphMetricsUpdater : public nsRunnable { 1.134 +public: 1.135 + NS_DECL_NSIRUNNABLE 1.136 + GlyphMetricsUpdater(SVGTextFrame* aFrame) : mFrame(aFrame) { } 1.137 + static void Run(SVGTextFrame* aFrame); 1.138 + void Revoke() { mFrame = nullptr; } 1.139 +private: 1.140 + SVGTextFrame* mFrame; 1.141 +}; 1.142 + 1.143 +// Slightly horrible callback for deferring application of opacity 1.144 +struct SVGTextContextPaint : public gfxTextContextPaint { 1.145 + already_AddRefed<gfxPattern> GetFillPattern(float aOpacity, 1.146 + const gfxMatrix& aCTM) MOZ_OVERRIDE; 1.147 + already_AddRefed<gfxPattern> GetStrokePattern(float aOpacity, 1.148 + const gfxMatrix& aCTM) MOZ_OVERRIDE; 1.149 + 1.150 + void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; } 1.151 + float GetFillOpacity() MOZ_OVERRIDE { return mFillOpacity; } 1.152 + 1.153 + void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; } 1.154 + float GetStrokeOpacity() MOZ_OVERRIDE { return mStrokeOpacity; } 1.155 + 1.156 + struct Paint { 1.157 + Paint() : mPaintType(eStyleSVGPaintType_None) {} 1.158 + 1.159 + void SetPaintServer(nsIFrame *aFrame, const gfxMatrix& aContextMatrix, 1.160 + nsSVGPaintServerFrame *aPaintServerFrame) { 1.161 + mPaintType = eStyleSVGPaintType_Server; 1.162 + mPaintDefinition.mPaintServerFrame = aPaintServerFrame; 1.163 + mFrame = aFrame; 1.164 + mContextMatrix = aContextMatrix; 1.165 + } 1.166 + 1.167 + void SetColor(const nscolor &aColor) { 1.168 + mPaintType = eStyleSVGPaintType_Color; 1.169 + mPaintDefinition.mColor = aColor; 1.170 + } 1.171 + 1.172 + void SetContextPaint(gfxTextContextPaint *aContextPaint, 1.173 + nsStyleSVGPaintType aPaintType) { 1.174 + NS_ASSERTION(aPaintType == eStyleSVGPaintType_ContextFill || 1.175 + aPaintType == eStyleSVGPaintType_ContextStroke, 1.176 + "Invalid context paint type"); 1.177 + mPaintType = aPaintType; 1.178 + mPaintDefinition.mContextPaint = aContextPaint; 1.179 + } 1.180 + 1.181 + union { 1.182 + nsSVGPaintServerFrame *mPaintServerFrame; 1.183 + gfxTextContextPaint *mContextPaint; 1.184 + nscolor mColor; 1.185 + } mPaintDefinition; 1.186 + 1.187 + nsIFrame *mFrame; 1.188 + // CTM defining the user space for the pattern we will use. 1.189 + gfxMatrix mContextMatrix; 1.190 + nsStyleSVGPaintType mPaintType; 1.191 + 1.192 + // Device-space-to-pattern-space 1.193 + gfxMatrix mPatternMatrix; 1.194 + nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache; 1.195 + 1.196 + already_AddRefed<gfxPattern> GetPattern(float aOpacity, 1.197 + nsStyleSVGPaint nsStyleSVG::*aFillOrStroke, 1.198 + const gfxMatrix& aCTM); 1.199 + }; 1.200 + 1.201 + Paint mFillPaint; 1.202 + Paint mStrokePaint; 1.203 + 1.204 + float mFillOpacity; 1.205 + float mStrokeOpacity; 1.206 +}; 1.207 + 1.208 +} // namespace mozilla 1.209 + 1.210 +/** 1.211 + * Frame class for SVG <text> elements, used when the 1.212 + * layout.svg.css-text.enabled is true. 1.213 + * 1.214 + * An SVGTextFrame manages SVG text layout, painting and interaction for 1.215 + * all descendent text content elements. The frame tree will look like this: 1.216 + * 1.217 + * SVGTextFrame -- for <text> 1.218 + * <anonymous block frame> 1.219 + * ns{Block,Inline,Text}Frames -- for text nodes, <tspan>s, <a>s, etc. 1.220 + * 1.221 + * SVG text layout is done by: 1.222 + * 1.223 + * 1. Reflowing the anonymous block frame. 1.224 + * 2. Inspecting the (app unit) positions of the glyph for each character in 1.225 + * the nsTextFrames underneath the anonymous block frame. 1.226 + * 3. Determining the (user unit) positions for each character in the <text> 1.227 + * using the x/y/dx/dy/rotate attributes on all the text content elements, 1.228 + * and using the step 2 results to fill in any gaps. 1.229 + * 4. Applying any other SVG specific text layout (anchoring and text paths) 1.230 + * to the positions computed in step 3. 1.231 + * 1.232 + * Rendering of the text is done by splitting up each nsTextFrame into ranges 1.233 + * that can be contiguously painted. (For example <text x="10 20">abcd</text> 1.234 + * would have two contiguous ranges: one for the "a" and one for the "bcd".) 1.235 + * Each range is called a "text rendered run", represented by a TextRenderedRun 1.236 + * object. The TextRenderedRunIterator class performs that splitting and 1.237 + * returns a TextRenderedRun for each bit of text to be painted separately. 1.238 + * 1.239 + * Each rendered run is painted by calling nsTextFrame::PaintText. If the text 1.240 + * formatting is simple enough (solid fill, no stroking, etc.), PaintText will 1.241 + * itself do the painting. Otherwise, a DrawPathCallback is passed to 1.242 + * PaintText so that we can fill the text geometry with SVG paint servers. 1.243 + */ 1.244 +class SVGTextFrame : public SVGTextFrameBase 1.245 +{ 1.246 + friend nsIFrame* 1.247 + NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.248 + 1.249 + friend class mozilla::CharIterator; 1.250 + friend class mozilla::GlyphMetricsUpdater; 1.251 + friend class mozilla::TextFrameIterator; 1.252 + friend class mozilla::TextNodeCorrespondenceRecorder; 1.253 + friend struct mozilla::TextRenderedRun; 1.254 + friend class mozilla::TextRenderedRunIterator; 1.255 + friend class MutationObserver; 1.256 + friend class nsDisplaySVGText; 1.257 + 1.258 + typedef mozilla::gfx::Path Path; 1.259 + typedef mozilla::SVGTextContextPaint SVGTextContextPaint; 1.260 + 1.261 +protected: 1.262 + SVGTextFrame(nsStyleContext* aContext) 1.263 + : SVGTextFrameBase(aContext), 1.264 + mFontSizeScaleFactor(1.0f), 1.265 + mLastContextScale(1.0f), 1.266 + mLengthAdjustScaleFactor(1.0f) 1.267 + { 1.268 + AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY); 1.269 + } 1.270 + 1.271 +public: 1.272 + NS_DECL_QUERYFRAME_TARGET(SVGTextFrame) 1.273 + NS_DECL_QUERYFRAME 1.274 + NS_DECL_FRAMEARENA_HELPERS 1.275 + 1.276 + // nsIFrame: 1.277 + virtual void Init(nsIContent* aContent, 1.278 + nsIFrame* aParent, 1.279 + nsIFrame* aPrevInFlow) MOZ_OVERRIDE; 1.280 + 1.281 + virtual nsresult AttributeChanged(int32_t aNamespaceID, 1.282 + nsIAtom* aAttribute, 1.283 + int32_t aModType) MOZ_OVERRIDE; 1.284 + 1.285 + virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE 1.286 + { 1.287 + return GetFirstPrincipalChild()->GetContentInsertionFrame(); 1.288 + } 1.289 + 1.290 + virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.291 + const nsRect& aDirtyRect, 1.292 + const nsDisplayListSet& aLists) MOZ_OVERRIDE; 1.293 + 1.294 + /** 1.295 + * Get the "type" of the frame 1.296 + * 1.297 + * @see nsGkAtoms::svgTextFrame 1.298 + */ 1.299 + virtual nsIAtom* GetType() const MOZ_OVERRIDE; 1.300 + 1.301 +#ifdef DEBUG_FRAME_DUMP 1.302 + virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE 1.303 + { 1.304 + return MakeFrameName(NS_LITERAL_STRING("SVGText"), aResult); 1.305 + } 1.306 +#endif 1.307 + 1.308 + virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE; 1.309 + 1.310 + /** 1.311 + * Finds the nsTextFrame for the closest rendered run to the specified point. 1.312 + */ 1.313 + virtual void FindCloserFrameForSelection(nsPoint aPoint, 1.314 + FrameWithDistance* aCurrentBestFrame) MOZ_OVERRIDE; 1.315 + 1.316 + 1.317 + 1.318 + // nsISVGChildFrame interface: 1.319 + virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE; 1.320 + virtual nsresult PaintSVG(nsRenderingContext* aContext, 1.321 + const nsIntRect* aDirtyRect, 1.322 + nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE; 1.323 + virtual nsIFrame* GetFrameForPoint(const nsPoint& aPoint) MOZ_OVERRIDE; 1.324 + virtual void ReflowSVG() MOZ_OVERRIDE; 1.325 + virtual nsRect GetCoveredRegion() MOZ_OVERRIDE; 1.326 + virtual SVGBBox GetBBoxContribution(const Matrix& aToBBoxUserspace, 1.327 + uint32_t aFlags) MOZ_OVERRIDE; 1.328 + 1.329 + // nsSVGContainerFrame methods: 1.330 + virtual gfxMatrix GetCanvasTM(uint32_t aFor, 1.331 + nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE; 1.332 + 1.333 + // SVG DOM text methods: 1.334 + uint32_t GetNumberOfChars(nsIContent* aContent); 1.335 + float GetComputedTextLength(nsIContent* aContent); 1.336 + nsresult SelectSubString(nsIContent* aContent, uint32_t charnum, uint32_t nchars); 1.337 + nsresult GetSubStringLength(nsIContent* aContent, uint32_t charnum, 1.338 + uint32_t nchars, float* aResult); 1.339 + int32_t GetCharNumAtPosition(nsIContent* aContent, mozilla::nsISVGPoint* point); 1.340 + 1.341 + nsresult GetStartPositionOfChar(nsIContent* aContent, uint32_t aCharNum, 1.342 + mozilla::nsISVGPoint** aResult); 1.343 + nsresult GetEndPositionOfChar(nsIContent* aContent, uint32_t aCharNum, 1.344 + mozilla::nsISVGPoint** aResult); 1.345 + nsresult GetExtentOfChar(nsIContent* aContent, uint32_t aCharNum, 1.346 + mozilla::dom::SVGIRect** aResult); 1.347 + nsresult GetRotationOfChar(nsIContent* aContent, uint32_t aCharNum, 1.348 + float* aResult); 1.349 + 1.350 + // SVGTextFrame methods: 1.351 + 1.352 + /** 1.353 + * Schedules mPositions to be recomputed and the covered region to be 1.354 + * updated. 1.355 + */ 1.356 + void NotifyGlyphMetricsChange(); 1.357 + 1.358 + /** 1.359 + * Calls ScheduleReflowSVGNonDisplayText if this is a non-display frame, 1.360 + * and nsSVGUtils::ScheduleReflowSVG otherwise. 1.361 + */ 1.362 + void ScheduleReflowSVG(); 1.363 + 1.364 + /** 1.365 + * Reflows the anonymous block frame of this non-display SVGTextFrame. 1.366 + * 1.367 + * When we are under nsSVGDisplayContainerFrame::ReflowSVG, we need to 1.368 + * reflow any SVGTextFrame frames in the subtree in case they are 1.369 + * being observed (by being for example in a <mask>) and the change 1.370 + * that caused the reflow would not already have caused a reflow. 1.371 + * 1.372 + * Note that displayed SVGTextFrames are reflowed as needed, when PaintSVG 1.373 + * is called or some SVG DOM method is called on the element. 1.374 + */ 1.375 + void ReflowSVGNonDisplayText(); 1.376 + 1.377 + /** 1.378 + * This is a function that behaves similarly to nsSVGUtils::ScheduleReflowSVG, 1.379 + * but which will skip over any ancestor non-display container frames on the 1.380 + * way to the nsSVGOuterSVGFrame. It exists for the situation where a 1.381 + * non-display <text> element has changed and needs to ensure ReflowSVG will 1.382 + * be called on its closest display container frame, so that 1.383 + * nsSVGDisplayContainerFrame::ReflowSVG will call ReflowSVGNonDisplayText on 1.384 + * it. 1.385 + * 1.386 + * The only case where we have to do this is in response to a style change on 1.387 + * a non-display <text>; the only caller of ScheduleReflowSVGNonDisplayText 1.388 + * currently is SVGTextFrame::DidSetStyleContext. 1.389 + */ 1.390 + void ScheduleReflowSVGNonDisplayText(); 1.391 + 1.392 + /** 1.393 + * Updates the mFontSizeScaleFactor value by looking at the range of 1.394 + * font-sizes used within the <text>. 1.395 + * 1.396 + * @return Whether mFontSizeScaleFactor changed. 1.397 + */ 1.398 + bool UpdateFontSizeScaleFactor(); 1.399 + 1.400 + double GetFontSizeScaleFactor() const; 1.401 + 1.402 + /** 1.403 + * Takes a point from the <text> element's user space and 1.404 + * converts it to the appropriate frame user space of aChildFrame, 1.405 + * according to which rendered run the point hits. 1.406 + */ 1.407 + gfxPoint TransformFramePointToTextChild(const gfxPoint& aPoint, 1.408 + nsIFrame* aChildFrame); 1.409 + 1.410 + /** 1.411 + * Takes a rectangle, aRect, in the <text> element's user space, and 1.412 + * returns a rectangle in aChildFrame's frame user space that 1.413 + * covers intersections of aRect with each rendered run for text frames 1.414 + * within aChildFrame. 1.415 + */ 1.416 + gfxRect TransformFrameRectToTextChild(const gfxRect& aRect, 1.417 + nsIFrame* aChildFrame); 1.418 + 1.419 + /** 1.420 + * Takes an app unit rectangle in the coordinate space of a given descendant 1.421 + * frame of this frame, and returns a rectangle in the <text> element's user 1.422 + * space that covers all parts of rendered runs that intersect with the 1.423 + * rectangle. 1.424 + */ 1.425 + gfxRect TransformFrameRectFromTextChild(const nsRect& aRect, 1.426 + nsIFrame* aChildFrame); 1.427 + 1.428 +private: 1.429 + /** 1.430 + * Mutation observer used to watch for text positioning attribute changes 1.431 + * on descendent text content elements (like <tspan>s). 1.432 + */ 1.433 + class MutationObserver : public nsStubMutationObserver { 1.434 + public: 1.435 + MutationObserver() 1.436 + : mFrame(nullptr) 1.437 + { 1.438 + } 1.439 + 1.440 + void StartObserving(SVGTextFrame* aFrame) 1.441 + { 1.442 + NS_ASSERTION(!mFrame, "should not be observing yet!"); 1.443 + mFrame = aFrame; 1.444 + aFrame->GetContent()->AddMutationObserver(this); 1.445 + } 1.446 + 1.447 + virtual ~MutationObserver() 1.448 + { 1.449 + if (mFrame) { 1.450 + mFrame->GetContent()->RemoveMutationObserver(this); 1.451 + } 1.452 + } 1.453 + 1.454 + // nsISupports 1.455 + NS_DECL_ISUPPORTS 1.456 + 1.457 + // nsIMutationObserver 1.458 + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED 1.459 + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED 1.460 + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED 1.461 + NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED 1.462 + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED 1.463 + 1.464 + private: 1.465 + SVGTextFrame* mFrame; 1.466 + }; 1.467 + 1.468 + /** 1.469 + * Reflows the anonymous block child if it is dirty or has dirty 1.470 + * children, or if the SVGTextFrame itself is dirty. 1.471 + */ 1.472 + void MaybeReflowAnonymousBlockChild(); 1.473 + 1.474 + /** 1.475 + * Performs the actual work of reflowing the anonymous block child. 1.476 + */ 1.477 + void DoReflow(); 1.478 + 1.479 + /** 1.480 + * Recomputes mPositions by calling DoGlyphPositioning if this information 1.481 + * is out of date. 1.482 + */ 1.483 + void UpdateGlyphPositioning(); 1.484 + 1.485 + /** 1.486 + * Populates mPositions with positioning information for each character 1.487 + * within the <text>. 1.488 + */ 1.489 + void DoGlyphPositioning(); 1.490 + 1.491 + /** 1.492 + * Converts the specified index into mPositions to an addressable 1.493 + * character index (as can be used with the SVG DOM text methods) 1.494 + * relative to the specified text child content element. 1.495 + * 1.496 + * @param aIndex The global character index. 1.497 + * @param aContent The descendant text child content element that 1.498 + * the returned addressable index will be relative to; null 1.499 + * means the same as the <text> element. 1.500 + * @return The addressable index, or -1 if the index cannot be 1.501 + * represented as an addressable index relative to aContent. 1.502 + */ 1.503 + int32_t 1.504 + ConvertTextElementCharIndexToAddressableIndex(int32_t aIndex, 1.505 + nsIContent* aContent); 1.506 + 1.507 + /** 1.508 + * Recursive helper for ResolvePositions below. 1.509 + * 1.510 + * @param aContent The current node. 1.511 + * @param aIndex The current character index. 1.512 + * @param aInTextPath Whether we are currently under a <textPath> element. 1.513 + * @param aForceStartOfChunk Whether the next character we find should start a 1.514 + * new anchored chunk. 1.515 + * @return The character index we got up to. 1.516 + */ 1.517 + uint32_t ResolvePositions(nsIContent* aContent, uint32_t aIndex, 1.518 + bool aInTextPath, bool& aForceStartOfChunk, 1.519 + nsTArray<gfxPoint>& aDeltas); 1.520 + 1.521 + /** 1.522 + * Initializes mPositions with character position information based on 1.523 + * x/y/rotate attributes, leaving unspecified values in the array if a position 1.524 + * was not given for that character. Also fills aDeltas with values based on 1.525 + * dx/dy attributes. 1.526 + * 1.527 + * @param aRunPerGlyph Whether mPositions should record that a new run begins 1.528 + * at each glyph. 1.529 + * @return True if we recorded any positions. 1.530 + */ 1.531 + bool ResolvePositions(nsTArray<gfxPoint>& aDeltas, bool aRunPerGlyph); 1.532 + 1.533 + /** 1.534 + * Determines the position, in app units, of each character in the <text> as 1.535 + * laid out by reflow, and appends them to aPositions. Any characters that 1.536 + * are undisplayed or trimmed away just get the last position. 1.537 + */ 1.538 + void DetermineCharPositions(nsTArray<nsPoint>& aPositions); 1.539 + 1.540 + /** 1.541 + * Sets mStartOfChunk to true for each character in mPositions that starts a 1.542 + * line of text. 1.543 + */ 1.544 + void AdjustChunksForLineBreaks(); 1.545 + 1.546 + /** 1.547 + * Adjusts recorded character positions in mPositions to account for glyph 1.548 + * boundaries. Four things are done: 1.549 + * 1.550 + * 1. mClusterOrLigatureGroupMiddle is set to true for all such characters. 1.551 + * 1.552 + * 2. Any run and anchored chunk boundaries that begin in the middle of a 1.553 + * cluster/ligature group get moved to the start of the next 1.554 + * cluster/ligature group. 1.555 + * 1.556 + * 3. The position of any character in the middle of a cluster/ligature 1.557 + * group is updated to take into account partial ligatures and any 1.558 + * rotation the glyph as a whole has. (The values that come out of 1.559 + * DetermineCharPositions which then get written into mPositions in 1.560 + * ResolvePositions store the same position value for each part of the 1.561 + * ligature.) 1.562 + * 1.563 + * 4. The rotation of any character in the middle of a cluster/ligature 1.564 + * group is set to the rotation of the first character. 1.565 + */ 1.566 + void AdjustPositionsForClusters(); 1.567 + 1.568 + /** 1.569 + * Updates the character positions stored in mPositions to account for 1.570 + * text anchoring. 1.571 + */ 1.572 + void DoAnchoring(); 1.573 + 1.574 + /** 1.575 + * Updates character positions in mPositions for those characters inside a 1.576 + * <textPath>. 1.577 + */ 1.578 + void DoTextPathLayout(); 1.579 + 1.580 + /** 1.581 + * Returns whether we need to render the text using 1.582 + * nsTextFrame::DrawPathCallbacks rather than directly painting 1.583 + * the text frames. 1.584 + * 1.585 + * @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text 1.586 + * should be painted. 1.587 + */ 1.588 + bool ShouldRenderAsPath(nsRenderingContext* aContext, nsTextFrame* aFrame, 1.589 + bool& aShouldPaintSVGGlyphs); 1.590 + 1.591 + // Methods to get information for a <textPath> frame. 1.592 + nsIFrame* GetTextPathPathFrame(nsIFrame* aTextPathFrame); 1.593 + mozilla::TemporaryRef<Path> GetTextPath(nsIFrame* aTextPathFrame); 1.594 + gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame); 1.595 + gfxFloat GetStartOffset(nsIFrame* aTextPathFrame); 1.596 + 1.597 + DrawMode SetupCairoState(gfxContext* aContext, 1.598 + nsIFrame* aFrame, 1.599 + gfxTextContextPaint* aOuterContextPaint, 1.600 + gfxTextContextPaint** aThisContextPaint); 1.601 + 1.602 + /** 1.603 + * Sets up the stroke style for |aFrame| in |aContext| and stores stroke 1.604 + * pattern information in |aThisContextPaint|. 1.605 + */ 1.606 + bool SetupCairoStroke(gfxContext* aContext, 1.607 + nsIFrame* aFrame, 1.608 + gfxTextContextPaint* aOuterContextPaint, 1.609 + SVGTextContextPaint* aThisContextPaint); 1.610 + 1.611 + /** 1.612 + * Sets up the fill style for |aFrame| in |aContext| and stores fill pattern 1.613 + * information in |aThisContextPaint|. 1.614 + */ 1.615 + bool SetupCairoFill(gfxContext* aContext, 1.616 + nsIFrame* aFrame, 1.617 + gfxTextContextPaint* aOuterContextPaint, 1.618 + SVGTextContextPaint* aThisContextPaint); 1.619 + 1.620 + /** 1.621 + * Stores in |aTargetPaint| information on how to reconstruct the current 1.622 + * fill or stroke pattern. Will also set the paint opacity to transparent if 1.623 + * the paint is set to "none". 1.624 + * @param aOuterContextPaint pattern information from the outer text context 1.625 + * @param aTargetPaint where to store the current pattern information 1.626 + * @param aFillOrStroke member pointer to the paint we are setting up 1.627 + * @param aProperty the frame property descriptor of the fill or stroke paint 1.628 + * server frame 1.629 + */ 1.630 + void SetupInheritablePaint(gfxContext* aContext, 1.631 + nsIFrame* aFrame, 1.632 + float& aOpacity, 1.633 + gfxTextContextPaint* aOuterContextPaint, 1.634 + SVGTextContextPaint::Paint& aTargetPaint, 1.635 + nsStyleSVGPaint nsStyleSVG::*aFillOrStroke, 1.636 + const FramePropertyDescriptor* aProperty); 1.637 + 1.638 + /** 1.639 + * The MutationObserver we have registered for the <text> element subtree. 1.640 + */ 1.641 + MutationObserver mMutationObserver; 1.642 + 1.643 + /** 1.644 + * Cached canvasTM value. 1.645 + */ 1.646 + nsAutoPtr<gfxMatrix> mCanvasTM; 1.647 + 1.648 + /** 1.649 + * The number of characters in the DOM after the final nsTextFrame. For 1.650 + * example, with 1.651 + * 1.652 + * <text>abcd<tspan display="none">ef</tspan></text> 1.653 + * 1.654 + * mTrailingUndisplayedCharacters would be 2. 1.655 + */ 1.656 + uint32_t mTrailingUndisplayedCharacters; 1.657 + 1.658 + /** 1.659 + * Computed position information for each DOM character within the <text>. 1.660 + */ 1.661 + nsTArray<mozilla::CharPosition> mPositions; 1.662 + 1.663 + /** 1.664 + * mFontSizeScaleFactor is used to cause the nsTextFrames to create text 1.665 + * runs with a font size different from the actual font-size property value. 1.666 + * This is used so that, for example with: 1.667 + * 1.668 + * <svg> 1.669 + * <g transform="scale(2)"> 1.670 + * <text font-size="10">abc</text> 1.671 + * </g> 1.672 + * </svg> 1.673 + * 1.674 + * a font size of 20 would be used. It's preferable to use a font size that 1.675 + * is identical or close to the size that the text will appear on the screen, 1.676 + * because at very small or large font sizes, text metrics will be computed 1.677 + * differently due to the limited precision that text runs have. 1.678 + * 1.679 + * mFontSizeScaleFactor is the amount the actual font-size property value 1.680 + * should be multiplied by to cause the text run font size to (a) be within a 1.681 + * "reasonable" range, and (b) be close to the actual size to be painted on 1.682 + * screen. (The "reasonable" range as determined by some #defines in 1.683 + * SVGTextFrame.cpp is 8..200.) 1.684 + */ 1.685 + float mFontSizeScaleFactor; 1.686 + 1.687 + /** 1.688 + * The scale of the context that we last used to compute mFontSizeScaleFactor. 1.689 + * We record this so that we can tell when our scale transform has changed 1.690 + * enough to warrant reflowing the text. 1.691 + */ 1.692 + float mLastContextScale; 1.693 + 1.694 + /** 1.695 + * The amount that we need to scale each rendered run to account for 1.696 + * lengthAdjust="spacingAndGlyphs". 1.697 + */ 1.698 + float mLengthAdjustScaleFactor; 1.699 +}; 1.700 + 1.701 +#endif