Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef MOZILLA_SVGTEXTFRAME_H
7 #define MOZILLA_SVGTEXTFRAME_H
9 #include "mozilla/Attributes.h"
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/gfx/2D.h"
12 #include "gfxMatrix.h"
13 #include "gfxRect.h"
14 #include "gfxSVGGlyphs.h"
15 #include "nsIContent.h"
16 #include "nsStubMutationObserver.h"
17 #include "nsSVGPaintServerFrame.h"
19 class nsDisplaySVGText;
20 class nsRenderingContext;
21 class SVGTextFrame;
22 class nsTextFrame;
24 typedef nsSVGDisplayContainerFrame SVGTextFrameBase;
26 namespace mozilla {
28 class CharIterator;
29 class nsISVGPoint;
30 class TextFrameIterator;
31 class TextNodeCorrespondenceRecorder;
32 struct TextRenderedRun;
33 class TextRenderedRunIterator;
35 namespace dom {
36 class SVGIRect;
37 }
39 /**
40 * Information about the positioning for a single character in an SVG <text>
41 * element.
42 *
43 * During SVG text layout, we use infinity values to represent positions and
44 * rotations that are not explicitly specified with x/y/rotate attributes.
45 */
46 struct CharPosition
47 {
48 CharPosition()
49 : mAngle(0),
50 mHidden(false),
51 mUnaddressable(false),
52 mClusterOrLigatureGroupMiddle(false),
53 mRunBoundary(false),
54 mStartOfChunk(false)
55 {
56 }
58 CharPosition(gfxPoint aPosition, double aAngle)
59 : mPosition(aPosition),
60 mAngle(aAngle),
61 mHidden(false),
62 mUnaddressable(false),
63 mClusterOrLigatureGroupMiddle(false),
64 mRunBoundary(false),
65 mStartOfChunk(false)
66 {
67 }
69 static CharPosition Unspecified(bool aUnaddressable)
70 {
71 CharPosition cp(UnspecifiedPoint(), UnspecifiedAngle());
72 cp.mUnaddressable = aUnaddressable;
73 return cp;
74 }
76 bool IsAngleSpecified() const
77 {
78 return mAngle != UnspecifiedAngle();
79 }
81 bool IsXSpecified() const
82 {
83 return mPosition.x != UnspecifiedCoord();
84 }
86 bool IsYSpecified() const
87 {
88 return mPosition.y != UnspecifiedCoord();
89 }
91 gfxPoint mPosition;
92 double mAngle;
94 // not displayed due to falling off the end of a <textPath>
95 bool mHidden;
97 // skipped in positioning attributes due to being collapsed-away white space
98 bool mUnaddressable;
100 // a preceding character is what positioning attributes address
101 bool mClusterOrLigatureGroupMiddle;
103 // rendering is split here since an explicit position or rotation was given
104 bool mRunBoundary;
106 // an anchored chunk begins here
107 bool mStartOfChunk;
109 private:
110 static gfxFloat UnspecifiedCoord()
111 {
112 return std::numeric_limits<gfxFloat>::infinity();
113 }
115 static double UnspecifiedAngle()
116 {
117 return std::numeric_limits<double>::infinity();
118 }
120 static gfxPoint UnspecifiedPoint()
121 {
122 return gfxPoint(UnspecifiedCoord(), UnspecifiedCoord());
123 }
124 };
126 /**
127 * A runnable to mark glyph positions as needing to be recomputed
128 * and to invalid the bounds of the SVGTextFrame frame.
129 */
130 class GlyphMetricsUpdater : public nsRunnable {
131 public:
132 NS_DECL_NSIRUNNABLE
133 GlyphMetricsUpdater(SVGTextFrame* aFrame) : mFrame(aFrame) { }
134 static void Run(SVGTextFrame* aFrame);
135 void Revoke() { mFrame = nullptr; }
136 private:
137 SVGTextFrame* mFrame;
138 };
140 // Slightly horrible callback for deferring application of opacity
141 struct SVGTextContextPaint : public gfxTextContextPaint {
142 already_AddRefed<gfxPattern> GetFillPattern(float aOpacity,
143 const gfxMatrix& aCTM) MOZ_OVERRIDE;
144 already_AddRefed<gfxPattern> GetStrokePattern(float aOpacity,
145 const gfxMatrix& aCTM) MOZ_OVERRIDE;
147 void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; }
148 float GetFillOpacity() MOZ_OVERRIDE { return mFillOpacity; }
150 void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; }
151 float GetStrokeOpacity() MOZ_OVERRIDE { return mStrokeOpacity; }
153 struct Paint {
154 Paint() : mPaintType(eStyleSVGPaintType_None) {}
156 void SetPaintServer(nsIFrame *aFrame, const gfxMatrix& aContextMatrix,
157 nsSVGPaintServerFrame *aPaintServerFrame) {
158 mPaintType = eStyleSVGPaintType_Server;
159 mPaintDefinition.mPaintServerFrame = aPaintServerFrame;
160 mFrame = aFrame;
161 mContextMatrix = aContextMatrix;
162 }
164 void SetColor(const nscolor &aColor) {
165 mPaintType = eStyleSVGPaintType_Color;
166 mPaintDefinition.mColor = aColor;
167 }
169 void SetContextPaint(gfxTextContextPaint *aContextPaint,
170 nsStyleSVGPaintType aPaintType) {
171 NS_ASSERTION(aPaintType == eStyleSVGPaintType_ContextFill ||
172 aPaintType == eStyleSVGPaintType_ContextStroke,
173 "Invalid context paint type");
174 mPaintType = aPaintType;
175 mPaintDefinition.mContextPaint = aContextPaint;
176 }
178 union {
179 nsSVGPaintServerFrame *mPaintServerFrame;
180 gfxTextContextPaint *mContextPaint;
181 nscolor mColor;
182 } mPaintDefinition;
184 nsIFrame *mFrame;
185 // CTM defining the user space for the pattern we will use.
186 gfxMatrix mContextMatrix;
187 nsStyleSVGPaintType mPaintType;
189 // Device-space-to-pattern-space
190 gfxMatrix mPatternMatrix;
191 nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache;
193 already_AddRefed<gfxPattern> GetPattern(float aOpacity,
194 nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
195 const gfxMatrix& aCTM);
196 };
198 Paint mFillPaint;
199 Paint mStrokePaint;
201 float mFillOpacity;
202 float mStrokeOpacity;
203 };
205 } // namespace mozilla
207 /**
208 * Frame class for SVG <text> elements, used when the
209 * layout.svg.css-text.enabled is true.
210 *
211 * An SVGTextFrame manages SVG text layout, painting and interaction for
212 * all descendent text content elements. The frame tree will look like this:
213 *
214 * SVGTextFrame -- for <text>
215 * <anonymous block frame>
216 * ns{Block,Inline,Text}Frames -- for text nodes, <tspan>s, <a>s, etc.
217 *
218 * SVG text layout is done by:
219 *
220 * 1. Reflowing the anonymous block frame.
221 * 2. Inspecting the (app unit) positions of the glyph for each character in
222 * the nsTextFrames underneath the anonymous block frame.
223 * 3. Determining the (user unit) positions for each character in the <text>
224 * using the x/y/dx/dy/rotate attributes on all the text content elements,
225 * and using the step 2 results to fill in any gaps.
226 * 4. Applying any other SVG specific text layout (anchoring and text paths)
227 * to the positions computed in step 3.
228 *
229 * Rendering of the text is done by splitting up each nsTextFrame into ranges
230 * that can be contiguously painted. (For example <text x="10 20">abcd</text>
231 * would have two contiguous ranges: one for the "a" and one for the "bcd".)
232 * Each range is called a "text rendered run", represented by a TextRenderedRun
233 * object. The TextRenderedRunIterator class performs that splitting and
234 * returns a TextRenderedRun for each bit of text to be painted separately.
235 *
236 * Each rendered run is painted by calling nsTextFrame::PaintText. If the text
237 * formatting is simple enough (solid fill, no stroking, etc.), PaintText will
238 * itself do the painting. Otherwise, a DrawPathCallback is passed to
239 * PaintText so that we can fill the text geometry with SVG paint servers.
240 */
241 class SVGTextFrame : public SVGTextFrameBase
242 {
243 friend nsIFrame*
244 NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
246 friend class mozilla::CharIterator;
247 friend class mozilla::GlyphMetricsUpdater;
248 friend class mozilla::TextFrameIterator;
249 friend class mozilla::TextNodeCorrespondenceRecorder;
250 friend struct mozilla::TextRenderedRun;
251 friend class mozilla::TextRenderedRunIterator;
252 friend class MutationObserver;
253 friend class nsDisplaySVGText;
255 typedef mozilla::gfx::Path Path;
256 typedef mozilla::SVGTextContextPaint SVGTextContextPaint;
258 protected:
259 SVGTextFrame(nsStyleContext* aContext)
260 : SVGTextFrameBase(aContext),
261 mFontSizeScaleFactor(1.0f),
262 mLastContextScale(1.0f),
263 mLengthAdjustScaleFactor(1.0f)
264 {
265 AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
266 }
268 public:
269 NS_DECL_QUERYFRAME_TARGET(SVGTextFrame)
270 NS_DECL_QUERYFRAME
271 NS_DECL_FRAMEARENA_HELPERS
273 // nsIFrame:
274 virtual void Init(nsIContent* aContent,
275 nsIFrame* aParent,
276 nsIFrame* aPrevInFlow) MOZ_OVERRIDE;
278 virtual nsresult AttributeChanged(int32_t aNamespaceID,
279 nsIAtom* aAttribute,
280 int32_t aModType) MOZ_OVERRIDE;
282 virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE
283 {
284 return GetFirstPrincipalChild()->GetContentInsertionFrame();
285 }
287 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
288 const nsRect& aDirtyRect,
289 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
291 /**
292 * Get the "type" of the frame
293 *
294 * @see nsGkAtoms::svgTextFrame
295 */
296 virtual nsIAtom* GetType() const MOZ_OVERRIDE;
298 #ifdef DEBUG_FRAME_DUMP
299 virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
300 {
301 return MakeFrameName(NS_LITERAL_STRING("SVGText"), aResult);
302 }
303 #endif
305 virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE;
307 /**
308 * Finds the nsTextFrame for the closest rendered run to the specified point.
309 */
310 virtual void FindCloserFrameForSelection(nsPoint aPoint,
311 FrameWithDistance* aCurrentBestFrame) MOZ_OVERRIDE;
315 // nsISVGChildFrame interface:
316 virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE;
317 virtual nsresult PaintSVG(nsRenderingContext* aContext,
318 const nsIntRect* aDirtyRect,
319 nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
320 virtual nsIFrame* GetFrameForPoint(const nsPoint& aPoint) MOZ_OVERRIDE;
321 virtual void ReflowSVG() MOZ_OVERRIDE;
322 virtual nsRect GetCoveredRegion() MOZ_OVERRIDE;
323 virtual SVGBBox GetBBoxContribution(const Matrix& aToBBoxUserspace,
324 uint32_t aFlags) MOZ_OVERRIDE;
326 // nsSVGContainerFrame methods:
327 virtual gfxMatrix GetCanvasTM(uint32_t aFor,
328 nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
330 // SVG DOM text methods:
331 uint32_t GetNumberOfChars(nsIContent* aContent);
332 float GetComputedTextLength(nsIContent* aContent);
333 nsresult SelectSubString(nsIContent* aContent, uint32_t charnum, uint32_t nchars);
334 nsresult GetSubStringLength(nsIContent* aContent, uint32_t charnum,
335 uint32_t nchars, float* aResult);
336 int32_t GetCharNumAtPosition(nsIContent* aContent, mozilla::nsISVGPoint* point);
338 nsresult GetStartPositionOfChar(nsIContent* aContent, uint32_t aCharNum,
339 mozilla::nsISVGPoint** aResult);
340 nsresult GetEndPositionOfChar(nsIContent* aContent, uint32_t aCharNum,
341 mozilla::nsISVGPoint** aResult);
342 nsresult GetExtentOfChar(nsIContent* aContent, uint32_t aCharNum,
343 mozilla::dom::SVGIRect** aResult);
344 nsresult GetRotationOfChar(nsIContent* aContent, uint32_t aCharNum,
345 float* aResult);
347 // SVGTextFrame methods:
349 /**
350 * Schedules mPositions to be recomputed and the covered region to be
351 * updated.
352 */
353 void NotifyGlyphMetricsChange();
355 /**
356 * Calls ScheduleReflowSVGNonDisplayText if this is a non-display frame,
357 * and nsSVGUtils::ScheduleReflowSVG otherwise.
358 */
359 void ScheduleReflowSVG();
361 /**
362 * Reflows the anonymous block frame of this non-display SVGTextFrame.
363 *
364 * When we are under nsSVGDisplayContainerFrame::ReflowSVG, we need to
365 * reflow any SVGTextFrame frames in the subtree in case they are
366 * being observed (by being for example in a <mask>) and the change
367 * that caused the reflow would not already have caused a reflow.
368 *
369 * Note that displayed SVGTextFrames are reflowed as needed, when PaintSVG
370 * is called or some SVG DOM method is called on the element.
371 */
372 void ReflowSVGNonDisplayText();
374 /**
375 * This is a function that behaves similarly to nsSVGUtils::ScheduleReflowSVG,
376 * but which will skip over any ancestor non-display container frames on the
377 * way to the nsSVGOuterSVGFrame. It exists for the situation where a
378 * non-display <text> element has changed and needs to ensure ReflowSVG will
379 * be called on its closest display container frame, so that
380 * nsSVGDisplayContainerFrame::ReflowSVG will call ReflowSVGNonDisplayText on
381 * it.
382 *
383 * The only case where we have to do this is in response to a style change on
384 * a non-display <text>; the only caller of ScheduleReflowSVGNonDisplayText
385 * currently is SVGTextFrame::DidSetStyleContext.
386 */
387 void ScheduleReflowSVGNonDisplayText();
389 /**
390 * Updates the mFontSizeScaleFactor value by looking at the range of
391 * font-sizes used within the <text>.
392 *
393 * @return Whether mFontSizeScaleFactor changed.
394 */
395 bool UpdateFontSizeScaleFactor();
397 double GetFontSizeScaleFactor() const;
399 /**
400 * Takes a point from the <text> element's user space and
401 * converts it to the appropriate frame user space of aChildFrame,
402 * according to which rendered run the point hits.
403 */
404 gfxPoint TransformFramePointToTextChild(const gfxPoint& aPoint,
405 nsIFrame* aChildFrame);
407 /**
408 * Takes a rectangle, aRect, in the <text> element's user space, and
409 * returns a rectangle in aChildFrame's frame user space that
410 * covers intersections of aRect with each rendered run for text frames
411 * within aChildFrame.
412 */
413 gfxRect TransformFrameRectToTextChild(const gfxRect& aRect,
414 nsIFrame* aChildFrame);
416 /**
417 * Takes an app unit rectangle in the coordinate space of a given descendant
418 * frame of this frame, and returns a rectangle in the <text> element's user
419 * space that covers all parts of rendered runs that intersect with the
420 * rectangle.
421 */
422 gfxRect TransformFrameRectFromTextChild(const nsRect& aRect,
423 nsIFrame* aChildFrame);
425 private:
426 /**
427 * Mutation observer used to watch for text positioning attribute changes
428 * on descendent text content elements (like <tspan>s).
429 */
430 class MutationObserver : public nsStubMutationObserver {
431 public:
432 MutationObserver()
433 : mFrame(nullptr)
434 {
435 }
437 void StartObserving(SVGTextFrame* aFrame)
438 {
439 NS_ASSERTION(!mFrame, "should not be observing yet!");
440 mFrame = aFrame;
441 aFrame->GetContent()->AddMutationObserver(this);
442 }
444 virtual ~MutationObserver()
445 {
446 if (mFrame) {
447 mFrame->GetContent()->RemoveMutationObserver(this);
448 }
449 }
451 // nsISupports
452 NS_DECL_ISUPPORTS
454 // nsIMutationObserver
455 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
456 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
457 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
458 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
459 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
461 private:
462 SVGTextFrame* mFrame;
463 };
465 /**
466 * Reflows the anonymous block child if it is dirty or has dirty
467 * children, or if the SVGTextFrame itself is dirty.
468 */
469 void MaybeReflowAnonymousBlockChild();
471 /**
472 * Performs the actual work of reflowing the anonymous block child.
473 */
474 void DoReflow();
476 /**
477 * Recomputes mPositions by calling DoGlyphPositioning if this information
478 * is out of date.
479 */
480 void UpdateGlyphPositioning();
482 /**
483 * Populates mPositions with positioning information for each character
484 * within the <text>.
485 */
486 void DoGlyphPositioning();
488 /**
489 * Converts the specified index into mPositions to an addressable
490 * character index (as can be used with the SVG DOM text methods)
491 * relative to the specified text child content element.
492 *
493 * @param aIndex The global character index.
494 * @param aContent The descendant text child content element that
495 * the returned addressable index will be relative to; null
496 * means the same as the <text> element.
497 * @return The addressable index, or -1 if the index cannot be
498 * represented as an addressable index relative to aContent.
499 */
500 int32_t
501 ConvertTextElementCharIndexToAddressableIndex(int32_t aIndex,
502 nsIContent* aContent);
504 /**
505 * Recursive helper for ResolvePositions below.
506 *
507 * @param aContent The current node.
508 * @param aIndex The current character index.
509 * @param aInTextPath Whether we are currently under a <textPath> element.
510 * @param aForceStartOfChunk Whether the next character we find should start a
511 * new anchored chunk.
512 * @return The character index we got up to.
513 */
514 uint32_t ResolvePositions(nsIContent* aContent, uint32_t aIndex,
515 bool aInTextPath, bool& aForceStartOfChunk,
516 nsTArray<gfxPoint>& aDeltas);
518 /**
519 * Initializes mPositions with character position information based on
520 * x/y/rotate attributes, leaving unspecified values in the array if a position
521 * was not given for that character. Also fills aDeltas with values based on
522 * dx/dy attributes.
523 *
524 * @param aRunPerGlyph Whether mPositions should record that a new run begins
525 * at each glyph.
526 * @return True if we recorded any positions.
527 */
528 bool ResolvePositions(nsTArray<gfxPoint>& aDeltas, bool aRunPerGlyph);
530 /**
531 * Determines the position, in app units, of each character in the <text> as
532 * laid out by reflow, and appends them to aPositions. Any characters that
533 * are undisplayed or trimmed away just get the last position.
534 */
535 void DetermineCharPositions(nsTArray<nsPoint>& aPositions);
537 /**
538 * Sets mStartOfChunk to true for each character in mPositions that starts a
539 * line of text.
540 */
541 void AdjustChunksForLineBreaks();
543 /**
544 * Adjusts recorded character positions in mPositions to account for glyph
545 * boundaries. Four things are done:
546 *
547 * 1. mClusterOrLigatureGroupMiddle is set to true for all such characters.
548 *
549 * 2. Any run and anchored chunk boundaries that begin in the middle of a
550 * cluster/ligature group get moved to the start of the next
551 * cluster/ligature group.
552 *
553 * 3. The position of any character in the middle of a cluster/ligature
554 * group is updated to take into account partial ligatures and any
555 * rotation the glyph as a whole has. (The values that come out of
556 * DetermineCharPositions which then get written into mPositions in
557 * ResolvePositions store the same position value for each part of the
558 * ligature.)
559 *
560 * 4. The rotation of any character in the middle of a cluster/ligature
561 * group is set to the rotation of the first character.
562 */
563 void AdjustPositionsForClusters();
565 /**
566 * Updates the character positions stored in mPositions to account for
567 * text anchoring.
568 */
569 void DoAnchoring();
571 /**
572 * Updates character positions in mPositions for those characters inside a
573 * <textPath>.
574 */
575 void DoTextPathLayout();
577 /**
578 * Returns whether we need to render the text using
579 * nsTextFrame::DrawPathCallbacks rather than directly painting
580 * the text frames.
581 *
582 * @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text
583 * should be painted.
584 */
585 bool ShouldRenderAsPath(nsRenderingContext* aContext, nsTextFrame* aFrame,
586 bool& aShouldPaintSVGGlyphs);
588 // Methods to get information for a <textPath> frame.
589 nsIFrame* GetTextPathPathFrame(nsIFrame* aTextPathFrame);
590 mozilla::TemporaryRef<Path> GetTextPath(nsIFrame* aTextPathFrame);
591 gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame);
592 gfxFloat GetStartOffset(nsIFrame* aTextPathFrame);
594 DrawMode SetupCairoState(gfxContext* aContext,
595 nsIFrame* aFrame,
596 gfxTextContextPaint* aOuterContextPaint,
597 gfxTextContextPaint** aThisContextPaint);
599 /**
600 * Sets up the stroke style for |aFrame| in |aContext| and stores stroke
601 * pattern information in |aThisContextPaint|.
602 */
603 bool SetupCairoStroke(gfxContext* aContext,
604 nsIFrame* aFrame,
605 gfxTextContextPaint* aOuterContextPaint,
606 SVGTextContextPaint* aThisContextPaint);
608 /**
609 * Sets up the fill style for |aFrame| in |aContext| and stores fill pattern
610 * information in |aThisContextPaint|.
611 */
612 bool SetupCairoFill(gfxContext* aContext,
613 nsIFrame* aFrame,
614 gfxTextContextPaint* aOuterContextPaint,
615 SVGTextContextPaint* aThisContextPaint);
617 /**
618 * Stores in |aTargetPaint| information on how to reconstruct the current
619 * fill or stroke pattern. Will also set the paint opacity to transparent if
620 * the paint is set to "none".
621 * @param aOuterContextPaint pattern information from the outer text context
622 * @param aTargetPaint where to store the current pattern information
623 * @param aFillOrStroke member pointer to the paint we are setting up
624 * @param aProperty the frame property descriptor of the fill or stroke paint
625 * server frame
626 */
627 void SetupInheritablePaint(gfxContext* aContext,
628 nsIFrame* aFrame,
629 float& aOpacity,
630 gfxTextContextPaint* aOuterContextPaint,
631 SVGTextContextPaint::Paint& aTargetPaint,
632 nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
633 const FramePropertyDescriptor* aProperty);
635 /**
636 * The MutationObserver we have registered for the <text> element subtree.
637 */
638 MutationObserver mMutationObserver;
640 /**
641 * Cached canvasTM value.
642 */
643 nsAutoPtr<gfxMatrix> mCanvasTM;
645 /**
646 * The number of characters in the DOM after the final nsTextFrame. For
647 * example, with
648 *
649 * <text>abcd<tspan display="none">ef</tspan></text>
650 *
651 * mTrailingUndisplayedCharacters would be 2.
652 */
653 uint32_t mTrailingUndisplayedCharacters;
655 /**
656 * Computed position information for each DOM character within the <text>.
657 */
658 nsTArray<mozilla::CharPosition> mPositions;
660 /**
661 * mFontSizeScaleFactor is used to cause the nsTextFrames to create text
662 * runs with a font size different from the actual font-size property value.
663 * This is used so that, for example with:
664 *
665 * <svg>
666 * <g transform="scale(2)">
667 * <text font-size="10">abc</text>
668 * </g>
669 * </svg>
670 *
671 * a font size of 20 would be used. It's preferable to use a font size that
672 * is identical or close to the size that the text will appear on the screen,
673 * because at very small or large font sizes, text metrics will be computed
674 * differently due to the limited precision that text runs have.
675 *
676 * mFontSizeScaleFactor is the amount the actual font-size property value
677 * should be multiplied by to cause the text run font size to (a) be within a
678 * "reasonable" range, and (b) be close to the actual size to be painted on
679 * screen. (The "reasonable" range as determined by some #defines in
680 * SVGTextFrame.cpp is 8..200.)
681 */
682 float mFontSizeScaleFactor;
684 /**
685 * The scale of the context that we last used to compute mFontSizeScaleFactor.
686 * We record this so that we can tell when our scale transform has changed
687 * enough to warrant reflowing the text.
688 */
689 float mLastContextScale;
691 /**
692 * The amount that we need to scale each rendered run to account for
693 * lengthAdjust="spacingAndGlyphs".
694 */
695 float mLengthAdjustScaleFactor;
696 };
698 #endif