| |
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/. */ |
| |
5 |
| |
6 #ifndef MOZILLA_SVGTEXTFRAME_H |
| |
7 #define MOZILLA_SVGTEXTFRAME_H |
| |
8 |
| |
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" |
| |
18 |
| |
19 class nsDisplaySVGText; |
| |
20 class nsRenderingContext; |
| |
21 class SVGTextFrame; |
| |
22 class nsTextFrame; |
| |
23 |
| |
24 typedef nsSVGDisplayContainerFrame SVGTextFrameBase; |
| |
25 |
| |
26 namespace mozilla { |
| |
27 |
| |
28 class CharIterator; |
| |
29 class nsISVGPoint; |
| |
30 class TextFrameIterator; |
| |
31 class TextNodeCorrespondenceRecorder; |
| |
32 struct TextRenderedRun; |
| |
33 class TextRenderedRunIterator; |
| |
34 |
| |
35 namespace dom { |
| |
36 class SVGIRect; |
| |
37 } |
| |
38 |
| |
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 } |
| |
57 |
| |
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 } |
| |
68 |
| |
69 static CharPosition Unspecified(bool aUnaddressable) |
| |
70 { |
| |
71 CharPosition cp(UnspecifiedPoint(), UnspecifiedAngle()); |
| |
72 cp.mUnaddressable = aUnaddressable; |
| |
73 return cp; |
| |
74 } |
| |
75 |
| |
76 bool IsAngleSpecified() const |
| |
77 { |
| |
78 return mAngle != UnspecifiedAngle(); |
| |
79 } |
| |
80 |
| |
81 bool IsXSpecified() const |
| |
82 { |
| |
83 return mPosition.x != UnspecifiedCoord(); |
| |
84 } |
| |
85 |
| |
86 bool IsYSpecified() const |
| |
87 { |
| |
88 return mPosition.y != UnspecifiedCoord(); |
| |
89 } |
| |
90 |
| |
91 gfxPoint mPosition; |
| |
92 double mAngle; |
| |
93 |
| |
94 // not displayed due to falling off the end of a <textPath> |
| |
95 bool mHidden; |
| |
96 |
| |
97 // skipped in positioning attributes due to being collapsed-away white space |
| |
98 bool mUnaddressable; |
| |
99 |
| |
100 // a preceding character is what positioning attributes address |
| |
101 bool mClusterOrLigatureGroupMiddle; |
| |
102 |
| |
103 // rendering is split here since an explicit position or rotation was given |
| |
104 bool mRunBoundary; |
| |
105 |
| |
106 // an anchored chunk begins here |
| |
107 bool mStartOfChunk; |
| |
108 |
| |
109 private: |
| |
110 static gfxFloat UnspecifiedCoord() |
| |
111 { |
| |
112 return std::numeric_limits<gfxFloat>::infinity(); |
| |
113 } |
| |
114 |
| |
115 static double UnspecifiedAngle() |
| |
116 { |
| |
117 return std::numeric_limits<double>::infinity(); |
| |
118 } |
| |
119 |
| |
120 static gfxPoint UnspecifiedPoint() |
| |
121 { |
| |
122 return gfxPoint(UnspecifiedCoord(), UnspecifiedCoord()); |
| |
123 } |
| |
124 }; |
| |
125 |
| |
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 }; |
| |
139 |
| |
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; |
| |
146 |
| |
147 void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; } |
| |
148 float GetFillOpacity() MOZ_OVERRIDE { return mFillOpacity; } |
| |
149 |
| |
150 void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; } |
| |
151 float GetStrokeOpacity() MOZ_OVERRIDE { return mStrokeOpacity; } |
| |
152 |
| |
153 struct Paint { |
| |
154 Paint() : mPaintType(eStyleSVGPaintType_None) {} |
| |
155 |
| |
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 } |
| |
163 |
| |
164 void SetColor(const nscolor &aColor) { |
| |
165 mPaintType = eStyleSVGPaintType_Color; |
| |
166 mPaintDefinition.mColor = aColor; |
| |
167 } |
| |
168 |
| |
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 } |
| |
177 |
| |
178 union { |
| |
179 nsSVGPaintServerFrame *mPaintServerFrame; |
| |
180 gfxTextContextPaint *mContextPaint; |
| |
181 nscolor mColor; |
| |
182 } mPaintDefinition; |
| |
183 |
| |
184 nsIFrame *mFrame; |
| |
185 // CTM defining the user space for the pattern we will use. |
| |
186 gfxMatrix mContextMatrix; |
| |
187 nsStyleSVGPaintType mPaintType; |
| |
188 |
| |
189 // Device-space-to-pattern-space |
| |
190 gfxMatrix mPatternMatrix; |
| |
191 nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache; |
| |
192 |
| |
193 already_AddRefed<gfxPattern> GetPattern(float aOpacity, |
| |
194 nsStyleSVGPaint nsStyleSVG::*aFillOrStroke, |
| |
195 const gfxMatrix& aCTM); |
| |
196 }; |
| |
197 |
| |
198 Paint mFillPaint; |
| |
199 Paint mStrokePaint; |
| |
200 |
| |
201 float mFillOpacity; |
| |
202 float mStrokeOpacity; |
| |
203 }; |
| |
204 |
| |
205 } // namespace mozilla |
| |
206 |
| |
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); |
| |
245 |
| |
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; |
| |
254 |
| |
255 typedef mozilla::gfx::Path Path; |
| |
256 typedef mozilla::SVGTextContextPaint SVGTextContextPaint; |
| |
257 |
| |
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 } |
| |
267 |
| |
268 public: |
| |
269 NS_DECL_QUERYFRAME_TARGET(SVGTextFrame) |
| |
270 NS_DECL_QUERYFRAME |
| |
271 NS_DECL_FRAMEARENA_HELPERS |
| |
272 |
| |
273 // nsIFrame: |
| |
274 virtual void Init(nsIContent* aContent, |
| |
275 nsIFrame* aParent, |
| |
276 nsIFrame* aPrevInFlow) MOZ_OVERRIDE; |
| |
277 |
| |
278 virtual nsresult AttributeChanged(int32_t aNamespaceID, |
| |
279 nsIAtom* aAttribute, |
| |
280 int32_t aModType) MOZ_OVERRIDE; |
| |
281 |
| |
282 virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE |
| |
283 { |
| |
284 return GetFirstPrincipalChild()->GetContentInsertionFrame(); |
| |
285 } |
| |
286 |
| |
287 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
| |
288 const nsRect& aDirtyRect, |
| |
289 const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
| |
290 |
| |
291 /** |
| |
292 * Get the "type" of the frame |
| |
293 * |
| |
294 * @see nsGkAtoms::svgTextFrame |
| |
295 */ |
| |
296 virtual nsIAtom* GetType() const MOZ_OVERRIDE; |
| |
297 |
| |
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 |
| |
304 |
| |
305 virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE; |
| |
306 |
| |
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; |
| |
312 |
| |
313 |
| |
314 |
| |
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; |
| |
325 |
| |
326 // nsSVGContainerFrame methods: |
| |
327 virtual gfxMatrix GetCanvasTM(uint32_t aFor, |
| |
328 nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE; |
| |
329 |
| |
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); |
| |
337 |
| |
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); |
| |
346 |
| |
347 // SVGTextFrame methods: |
| |
348 |
| |
349 /** |
| |
350 * Schedules mPositions to be recomputed and the covered region to be |
| |
351 * updated. |
| |
352 */ |
| |
353 void NotifyGlyphMetricsChange(); |
| |
354 |
| |
355 /** |
| |
356 * Calls ScheduleReflowSVGNonDisplayText if this is a non-display frame, |
| |
357 * and nsSVGUtils::ScheduleReflowSVG otherwise. |
| |
358 */ |
| |
359 void ScheduleReflowSVG(); |
| |
360 |
| |
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(); |
| |
373 |
| |
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(); |
| |
388 |
| |
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(); |
| |
396 |
| |
397 double GetFontSizeScaleFactor() const; |
| |
398 |
| |
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); |
| |
406 |
| |
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); |
| |
415 |
| |
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); |
| |
424 |
| |
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 } |
| |
436 |
| |
437 void StartObserving(SVGTextFrame* aFrame) |
| |
438 { |
| |
439 NS_ASSERTION(!mFrame, "should not be observing yet!"); |
| |
440 mFrame = aFrame; |
| |
441 aFrame->GetContent()->AddMutationObserver(this); |
| |
442 } |
| |
443 |
| |
444 virtual ~MutationObserver() |
| |
445 { |
| |
446 if (mFrame) { |
| |
447 mFrame->GetContent()->RemoveMutationObserver(this); |
| |
448 } |
| |
449 } |
| |
450 |
| |
451 // nsISupports |
| |
452 NS_DECL_ISUPPORTS |
| |
453 |
| |
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 |
| |
460 |
| |
461 private: |
| |
462 SVGTextFrame* mFrame; |
| |
463 }; |
| |
464 |
| |
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(); |
| |
470 |
| |
471 /** |
| |
472 * Performs the actual work of reflowing the anonymous block child. |
| |
473 */ |
| |
474 void DoReflow(); |
| |
475 |
| |
476 /** |
| |
477 * Recomputes mPositions by calling DoGlyphPositioning if this information |
| |
478 * is out of date. |
| |
479 */ |
| |
480 void UpdateGlyphPositioning(); |
| |
481 |
| |
482 /** |
| |
483 * Populates mPositions with positioning information for each character |
| |
484 * within the <text>. |
| |
485 */ |
| |
486 void DoGlyphPositioning(); |
| |
487 |
| |
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); |
| |
503 |
| |
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); |
| |
517 |
| |
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); |
| |
529 |
| |
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); |
| |
536 |
| |
537 /** |
| |
538 * Sets mStartOfChunk to true for each character in mPositions that starts a |
| |
539 * line of text. |
| |
540 */ |
| |
541 void AdjustChunksForLineBreaks(); |
| |
542 |
| |
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(); |
| |
564 |
| |
565 /** |
| |
566 * Updates the character positions stored in mPositions to account for |
| |
567 * text anchoring. |
| |
568 */ |
| |
569 void DoAnchoring(); |
| |
570 |
| |
571 /** |
| |
572 * Updates character positions in mPositions for those characters inside a |
| |
573 * <textPath>. |
| |
574 */ |
| |
575 void DoTextPathLayout(); |
| |
576 |
| |
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); |
| |
587 |
| |
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); |
| |
593 |
| |
594 DrawMode SetupCairoState(gfxContext* aContext, |
| |
595 nsIFrame* aFrame, |
| |
596 gfxTextContextPaint* aOuterContextPaint, |
| |
597 gfxTextContextPaint** aThisContextPaint); |
| |
598 |
| |
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); |
| |
607 |
| |
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); |
| |
616 |
| |
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); |
| |
634 |
| |
635 /** |
| |
636 * The MutationObserver we have registered for the <text> element subtree. |
| |
637 */ |
| |
638 MutationObserver mMutationObserver; |
| |
639 |
| |
640 /** |
| |
641 * Cached canvasTM value. |
| |
642 */ |
| |
643 nsAutoPtr<gfxMatrix> mCanvasTM; |
| |
644 |
| |
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; |
| |
654 |
| |
655 /** |
| |
656 * Computed position information for each DOM character within the <text>. |
| |
657 */ |
| |
658 nsTArray<mozilla::CharPosition> mPositions; |
| |
659 |
| |
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; |
| |
683 |
| |
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; |
| |
690 |
| |
691 /** |
| |
692 * The amount that we need to scale each rendered run to account for |
| |
693 * lengthAdjust="spacingAndGlyphs". |
| |
694 */ |
| |
695 float mLengthAdjustScaleFactor; |
| |
696 }; |
| |
697 |
| |
698 #endif |