/work/obj-fuzz/dist/include/gfxTextRun.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=4 et sw=4 tw=80: |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef GFX_TEXTRUN_H |
8 | | #define GFX_TEXTRUN_H |
9 | | |
10 | | #include <stdint.h> |
11 | | |
12 | | #include "gfxTypes.h" |
13 | | #include "gfxPoint.h" |
14 | | #include "gfxFont.h" |
15 | | #include "gfxFontConstants.h" |
16 | | #include "gfxSkipChars.h" |
17 | | #include "gfxPlatform.h" |
18 | | #include "mozilla/MemoryReporting.h" |
19 | | #include "mozilla/RefPtr.h" |
20 | | #include "nsPoint.h" |
21 | | #include "nsString.h" |
22 | | #include "nsTArray.h" |
23 | | #include "nsTextFrameUtils.h" |
24 | | #include "DrawMode.h" |
25 | | #include "harfbuzz/hb.h" |
26 | | #include "nsUnicodeScriptCodes.h" |
27 | | #include "nsColor.h" |
28 | | #include "X11UndefineNone.h" |
29 | | |
30 | | #ifdef DEBUG |
31 | | #include <stdio.h> |
32 | | #endif |
33 | | |
34 | | class gfxContext; |
35 | | class gfxFontGroup; |
36 | | class gfxUserFontEntry; |
37 | | class gfxUserFontSet; |
38 | | class nsAtom; |
39 | | class nsLanguageAtomService; |
40 | | class gfxMissingFontRecorder; |
41 | | |
42 | | namespace mozilla { |
43 | | class SVGContextPaint; |
44 | | enum class StyleHyphens : uint8_t; |
45 | | }; |
46 | | |
47 | | /** |
48 | | * Callback for Draw() to use when drawing text with mode |
49 | | * DrawMode::GLYPH_PATH. |
50 | | */ |
51 | | struct gfxTextRunDrawCallbacks { |
52 | | |
53 | | /** |
54 | | * Constructs a new DrawCallbacks object. |
55 | | * |
56 | | * @param aShouldPaintSVGGlyphs If true, SVG glyphs will be painted. If |
57 | | * false, SVG glyphs will not be painted; fallback plain glyphs are not |
58 | | * emitted either. |
59 | | */ |
60 | | explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false) |
61 | | : mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs) |
62 | 0 | { |
63 | 0 | } |
64 | | |
65 | | /** |
66 | | * Called when a path has been emitted to the gfxContext when |
67 | | * painting a text run. This can be called any number of times, |
68 | | * due to partial ligatures and intervening SVG glyphs. |
69 | | */ |
70 | | virtual void NotifyGlyphPathEmitted() = 0; |
71 | | |
72 | | bool mShouldPaintSVGGlyphs; |
73 | | }; |
74 | | |
75 | | /** |
76 | | * gfxTextRun is an abstraction for drawing and measuring substrings of a run |
77 | | * of text. It stores runs of positioned glyph data, each run having a single |
78 | | * gfxFont. The glyphs are associated with a string of source text, and the |
79 | | * gfxTextRun APIs take parameters that are offsets into that source text. |
80 | | * |
81 | | * gfxTextRuns are mostly immutable. The only things that can change are |
82 | | * inter-cluster spacing and line break placement. Spacing is always obtained |
83 | | * lazily by methods that need it, it is not cached. Line breaks are stored |
84 | | * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does |
85 | | * not actually do anything to explicitly account for line breaks). Initially |
86 | | * there are no line breaks. The textrun can record line breaks before or after |
87 | | * any given cluster. (Line breaks specified inside clusters are ignored.) |
88 | | * |
89 | | * It is important that zero-length substrings are handled correctly. This will |
90 | | * be on the test! |
91 | | */ |
92 | | class gfxTextRun : public gfxShapedText |
93 | | { |
94 | | NS_INLINE_DECL_REFCOUNTING(gfxTextRun); |
95 | | |
96 | | protected: |
97 | | // Override operator delete to properly free the object that was |
98 | | // allocated via malloc. |
99 | | void operator delete(void* p) { |
100 | | free(p); |
101 | | } |
102 | | |
103 | | virtual ~gfxTextRun(); |
104 | | |
105 | | public: |
106 | | typedef gfxFont::RunMetrics Metrics; |
107 | | typedef mozilla::gfx::DrawTarget DrawTarget; |
108 | | |
109 | | // Public textrun API for general use |
110 | | |
111 | 0 | bool IsClusterStart(uint32_t aPos) const { |
112 | 0 | MOZ_ASSERT(aPos < GetLength()); |
113 | 0 | return mCharacterGlyphs[aPos].IsClusterStart(); |
114 | 0 | } |
115 | 0 | bool IsLigatureGroupStart(uint32_t aPos) const { |
116 | 0 | MOZ_ASSERT(aPos < GetLength()); |
117 | 0 | return mCharacterGlyphs[aPos].IsLigatureGroupStart(); |
118 | 0 | } |
119 | 0 | bool CanBreakLineBefore(uint32_t aPos) const { |
120 | 0 | return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_NORMAL; |
121 | 0 | } |
122 | 0 | bool CanHyphenateBefore(uint32_t aPos) const { |
123 | 0 | return CanBreakBefore(aPos) == CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN; |
124 | 0 | } |
125 | | |
126 | | // Returns a gfxShapedText::CompressedGlyph::FLAG_BREAK_TYPE_* value |
127 | | // as defined in gfxFont.h (may be NONE, NORMAL or HYPHEN). |
128 | 0 | uint8_t CanBreakBefore(uint32_t aPos) const { |
129 | 0 | MOZ_ASSERT(aPos < GetLength()); |
130 | 0 | return mCharacterGlyphs[aPos].CanBreakBefore(); |
131 | 0 | } |
132 | | |
133 | 0 | bool CharIsSpace(uint32_t aPos) const { |
134 | 0 | MOZ_ASSERT(aPos < GetLength()); |
135 | 0 | return mCharacterGlyphs[aPos].CharIsSpace(); |
136 | 0 | } |
137 | 0 | bool CharIsTab(uint32_t aPos) const { |
138 | 0 | MOZ_ASSERT(aPos < GetLength()); |
139 | 0 | return mCharacterGlyphs[aPos].CharIsTab(); |
140 | 0 | } |
141 | 0 | bool CharIsNewline(uint32_t aPos) const { |
142 | 0 | MOZ_ASSERT(aPos < GetLength()); |
143 | 0 | return mCharacterGlyphs[aPos].CharIsNewline(); |
144 | 0 | } |
145 | 0 | bool CharMayHaveEmphasisMark(uint32_t aPos) const { |
146 | 0 | MOZ_ASSERT(aPos < GetLength()); |
147 | 0 | return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark(); |
148 | 0 | } |
149 | 0 | bool CharIsFormattingControl(uint32_t aPos) const { |
150 | 0 | MOZ_ASSERT(aPos < GetLength()); |
151 | 0 | return mCharacterGlyphs[aPos].CharIsFormattingControl(); |
152 | 0 | } |
153 | | |
154 | | // All offsets are in terms of the string passed into MakeTextRun. |
155 | | |
156 | | // Describe range [start, end) of a text run. The range is |
157 | | // restricted to grapheme cluster boundaries. |
158 | | struct Range |
159 | | { |
160 | | uint32_t start; |
161 | | uint32_t end; |
162 | | uint32_t Length() const { return end - start; } |
163 | | |
164 | | Range() : start(0), end(0) {} |
165 | | Range(uint32_t aStart, uint32_t aEnd) |
166 | 0 | : start(aStart), end(aEnd) {} |
167 | | explicit Range(const gfxTextRun* aTextRun) |
168 | 0 | : start(0), end(aTextRun->GetLength()) {} |
169 | | }; |
170 | | |
171 | | // All coordinates are in layout/app units |
172 | | |
173 | | /** |
174 | | * Set the potential linebreaks for a substring of the textrun. These are |
175 | | * the "allow break before" points. Initially, there are no potential |
176 | | * linebreaks. |
177 | | * |
178 | | * This can change glyphs and/or geometry! Some textruns' shapes |
179 | | * depend on potential line breaks (e.g., title-case-converting textruns). |
180 | | * This function is virtual so that those textruns can reshape themselves. |
181 | | * |
182 | | * @return true if this changed the linebreaks, false if the new line |
183 | | * breaks are the same as the old |
184 | | */ |
185 | | virtual bool SetPotentialLineBreaks(Range aRange, |
186 | | const uint8_t* aBreakBefore); |
187 | | |
188 | | enum class HyphenType : uint8_t { |
189 | | None, |
190 | | Explicit, |
191 | | Soft, |
192 | | AutoWithManualInSameWord, |
193 | | AutoWithoutManualInSameWord |
194 | | }; |
195 | | |
196 | | struct HyphenationState { |
197 | | uint32_t mostRecentBoundary = 0; |
198 | | bool hasManualHyphen = false; |
199 | | bool hasExplicitHyphen = false; |
200 | | bool hasAutoHyphen = false; |
201 | | }; |
202 | | |
203 | | /** |
204 | | * Layout provides PropertyProvider objects. These allow detection of |
205 | | * potential line break points and computation of spacing. We pass the data |
206 | | * this way to allow lazy data acquisition; for example BreakAndMeasureText |
207 | | * will want to only ask for properties of text it's actually looking at. |
208 | | * |
209 | | * NOTE that requested spacing may not actually be applied, if the textrun |
210 | | * is unable to apply it in some context. Exception: spacing around a |
211 | | * whitespace character MUST always be applied. |
212 | | */ |
213 | | class PropertyProvider { |
214 | | public: |
215 | | // Detect hyphenation break opportunities in the given range; breaks |
216 | | // not at cluster boundaries will be ignored. |
217 | | virtual void GetHyphenationBreaks(Range aRange, |
218 | | HyphenType *aBreakBefore) const = 0; |
219 | | |
220 | | // Returns the provider's hyphenation setting, so callers can decide |
221 | | // whether it is necessary to call GetHyphenationBreaks. |
222 | | // Result is an StyleHyphens value. |
223 | | virtual mozilla::StyleHyphens GetHyphensOption() const = 0; |
224 | | |
225 | | // Returns the extra width that will be consumed by a hyphen. This should |
226 | | // be constant for a given textrun. |
227 | | virtual gfxFloat GetHyphenWidth() const = 0; |
228 | | |
229 | | typedef gfxFont::Spacing Spacing; |
230 | | |
231 | | /** |
232 | | * Get the spacing around the indicated characters. Spacing must be zero |
233 | | * inside clusters. In other words, if character i is not |
234 | | * CLUSTER_START, then character i-1 must have zero after-spacing and |
235 | | * character i must have zero before-spacing. |
236 | | */ |
237 | | virtual void GetSpacing(Range aRange, Spacing *aSpacing) const = 0; |
238 | | |
239 | | // Returns a gfxContext that can be used to measure the hyphen glyph. |
240 | | // Only called if the hyphen width is requested. |
241 | | virtual already_AddRefed<DrawTarget> GetDrawTarget() const = 0; |
242 | | |
243 | | // Return the appUnitsPerDevUnit value to be used when measuring. |
244 | | // Only called if the hyphen width is requested. |
245 | | virtual uint32_t GetAppUnitsPerDevUnit() const = 0; |
246 | | }; |
247 | | |
248 | | struct MOZ_STACK_CLASS DrawParams |
249 | | { |
250 | | gfxContext* context; |
251 | | DrawMode drawMode = DrawMode::GLYPH_FILL; |
252 | | nscolor textStrokeColor = 0; |
253 | | gfxPattern* textStrokePattern = nullptr; |
254 | | const mozilla::gfx::StrokeOptions *strokeOpts = nullptr; |
255 | | const mozilla::gfx::DrawOptions *drawOpts = nullptr; |
256 | | PropertyProvider* provider = nullptr; |
257 | | // If non-null, the advance width of the substring is set. |
258 | | gfxFloat* advanceWidth = nullptr; |
259 | | mozilla::SVGContextPaint* contextPaint = nullptr; |
260 | | gfxTextRunDrawCallbacks* callbacks = nullptr; |
261 | 0 | explicit DrawParams(gfxContext* aContext) : context(aContext) {} |
262 | | }; |
263 | | |
264 | | /** |
265 | | * Draws a substring. Uses only GetSpacing from aBreakProvider. |
266 | | * The provided point is the baseline origin on the left of the string |
267 | | * for LTR, on the right of the string for RTL. |
268 | | * |
269 | | * Drawing should respect advance widths in the sense that for LTR runs, |
270 | | * Draw(Range(start, middle), pt, ...) followed by |
271 | | * Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...) |
272 | | * should have the same effect as |
273 | | * Draw(Range(start, end), pt, ...) |
274 | | * |
275 | | * For RTL runs the rule is: |
276 | | * Draw(Range(middle, end), pt, ...) followed by |
277 | | * Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...) |
278 | | * should have the same effect as |
279 | | * Draw(Range(start, end), pt, ...) |
280 | | * |
281 | | * Glyphs should be drawn in logical content order, which can be significant |
282 | | * if they overlap (perhaps due to negative spacing). |
283 | | */ |
284 | | void Draw(Range aRange, mozilla::gfx::Point aPt, |
285 | | const DrawParams& aParams) const; |
286 | | |
287 | | /** |
288 | | * Draws the emphasis marks for this text run. Uses only GetSpacing |
289 | | * from aProvider. The provided point is the baseline origin of the |
290 | | * line of emphasis marks. |
291 | | */ |
292 | | void DrawEmphasisMarks(gfxContext* aContext, |
293 | | gfxTextRun* aMark, |
294 | | gfxFloat aMarkAdvance, mozilla::gfx::Point aPt, |
295 | | Range aRange, PropertyProvider* aProvider) const; |
296 | | |
297 | | /** |
298 | | * Computes the ReflowMetrics for a substring. |
299 | | * Uses GetSpacing from aBreakProvider. |
300 | | * @param aBoundingBoxType which kind of bounding box (loose/tight) |
301 | | */ |
302 | | Metrics MeasureText(Range aRange, |
303 | | gfxFont::BoundingBoxType aBoundingBoxType, |
304 | | DrawTarget* aDrawTargetForTightBoundingBox, |
305 | | PropertyProvider* aProvider) const; |
306 | | |
307 | | Metrics MeasureText(gfxFont::BoundingBoxType aBoundingBoxType, |
308 | | DrawTarget* aDrawTargetForTightBoundingBox, |
309 | 0 | PropertyProvider* aProvider = nullptr) const { |
310 | 0 | return MeasureText(Range(this), aBoundingBoxType, |
311 | 0 | aDrawTargetForTightBoundingBox, aProvider); |
312 | 0 | } |
313 | | |
314 | | /** |
315 | | * Computes just the advance width for a substring. |
316 | | * Uses GetSpacing from aBreakProvider. |
317 | | * If aSpacing is not null, the spacing attached before and after |
318 | | * the substring would be returned in it. NOTE: the spacing is |
319 | | * included in the advance width. |
320 | | */ |
321 | | gfxFloat GetAdvanceWidth(Range aRange, PropertyProvider *aProvider, |
322 | | PropertyProvider::Spacing* |
323 | | aSpacing = nullptr) const; |
324 | | |
325 | | gfxFloat GetAdvanceWidth() const { |
326 | | return GetAdvanceWidth(Range(this), nullptr); |
327 | | } |
328 | | |
329 | | /** |
330 | | * Computes the minimum advance width for a substring assuming line |
331 | | * breaking is allowed everywhere. |
332 | | */ |
333 | | gfxFloat GetMinAdvanceWidth(Range aRange); |
334 | | |
335 | | /** |
336 | | * Clear all stored line breaks for the given range (both before and after), |
337 | | * and then set the line-break state before aRange.start to aBreakBefore and |
338 | | * after the last cluster to aBreakAfter. |
339 | | * |
340 | | * We require that before and after line breaks be consistent. For clusters |
341 | | * i and i+1, we require that if there is a break after cluster i, a break |
342 | | * will be specified before cluster i+1. This may be temporarily violated |
343 | | * (e.g. after reflowing line L and before reflowing line L+1); to handle |
344 | | * these temporary violations, we say that there is a break betwen i and i+1 |
345 | | * if a break is specified after i OR a break is specified before i+1. |
346 | | * |
347 | | * This can change textrun geometry! The existence of a linebreak can affect |
348 | | * the advance width of the cluster before the break (when kerning) or the |
349 | | * geometry of one cluster before the break or any number of clusters |
350 | | * after the break. (The one-cluster-before-the-break limit is somewhat |
351 | | * arbitrary; if some scripts require breaking it, then we need to |
352 | | * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase |
353 | | * it could affect the layout of frames before it...) |
354 | | * |
355 | | * We return true if glyphs or geometry changed, false otherwise. This |
356 | | * function is virtual so that gfxTextRun subclasses can reshape |
357 | | * properly. |
358 | | * |
359 | | * @param aAdvanceWidthDelta if non-null, returns the change in advance |
360 | | * width of the given range. |
361 | | */ |
362 | | virtual bool SetLineBreaks(Range aRange, |
363 | | bool aLineBreakBefore, bool aLineBreakAfter, |
364 | | gfxFloat* aAdvanceWidthDelta); |
365 | | |
366 | | enum SuppressBreak { |
367 | | eNoSuppressBreak, |
368 | | // Measure the range of text as if there is no break before it. |
369 | | eSuppressInitialBreak, |
370 | | // Measure the range of text as if it contains no break |
371 | | eSuppressAllBreaks |
372 | | }; |
373 | | |
374 | | void ClassifyAutoHyphenations(uint32_t aStart, Range aRange, |
375 | | nsTArray<HyphenType>& aHyphenBuffer, |
376 | | HyphenationState* aWordState); |
377 | | |
378 | | /** |
379 | | * Finds the longest substring that will fit into the given width. |
380 | | * Uses GetHyphenationBreaks and GetSpacing from aProvider. |
381 | | * Guarantees the following: |
382 | | * -- 0 <= result <= aMaxLength |
383 | | * -- result is the maximal value of N such that either |
384 | | * N < aMaxLength && line break at N && GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth |
385 | | * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(Range(aStart, N), aProvider) + GetHyphenWidth() <= aWidth |
386 | | * OR N == aMaxLength && GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth |
387 | | * where GetAdvanceWidth assumes the effect of |
388 | | * SetLineBreaks(Range(aStart, N), aLineBreakBefore, N < aMaxLength, aProvider) |
389 | | * -- if no such N exists, then result is the smallest N such that |
390 | | * N < aMaxLength && line break at N |
391 | | * OR N < aMaxLength && hyphen break at N |
392 | | * OR N == aMaxLength |
393 | | * |
394 | | * The call has the effect of |
395 | | * SetLineBreaks(Range(aStart, result), aLineBreakBefore, result < aMaxLength, aProvider) |
396 | | * and the returned metrics and the invariants above reflect this. |
397 | | * |
398 | | * @param aMaxLength this can be UINT32_MAX, in which case the length used |
399 | | * is up to the end of the string |
400 | | * @param aLineBreakBefore set to true if and only if there is an actual |
401 | | * line break at the start of this string. |
402 | | * @param aSuppressBreak what break should be suppressed. |
403 | | * @param aTrimWhitespace if non-null, then we allow a trailing run of |
404 | | * spaces to be trimmed; the width of the space(s) will not be included in |
405 | | * the measured string width for comparison with the limit aWidth, and |
406 | | * trimmed spaces will not be included in returned metrics. The width |
407 | | * of the trimmed spaces will be returned in aTrimWhitespace. |
408 | | * Trimmed spaces are still counted in the "characters fit" result. |
409 | | * @param aHangWhitespace true if we allow whitespace to overflow the |
410 | | * container at a soft-wrap |
411 | | * @param aMetrics if non-null, we fill this in for the returned substring. |
412 | | * If a hyphenation break was used, the hyphen is NOT included in the returned metrics. |
413 | | * @param aBoundingBoxType whether to make the bounding box in aMetrics tight |
414 | | * @param aDrawTargetForTightBoundingbox a reference DrawTarget to get the |
415 | | * tight bounding box, if requested |
416 | | * @param aUsedHyphenation if non-null, records if we selected a hyphenation break |
417 | | * @param aLastBreak if non-null and result is aMaxLength, we set this to |
418 | | * the maximal N such that |
419 | | * N < aMaxLength && line break at N && GetAdvanceWidth(Range(aStart, N), aProvider) <= aWidth |
420 | | * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(Range(aStart, N), aProvider) + GetHyphenWidth() <= aWidth |
421 | | * or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes |
422 | | * the effect of |
423 | | * SetLineBreaks(Range(aStart, N), aLineBreakBefore, N < aMaxLength, aProvider) |
424 | | * |
425 | | * @param aCanWordWrap true if we can break between any two grapheme |
426 | | * clusters. This is set by overflow-wrap|word-wrap: break-word |
427 | | * |
428 | | * @param aBreakPriority in/out the priority of the break opportunity |
429 | | * saved in the line. If we are prioritizing break opportunities, we will |
430 | | * not set a break with a lower priority. @see gfxBreakPriority. |
431 | | * |
432 | | * Note that negative advance widths are possible especially if negative |
433 | | * spacing is provided. |
434 | | */ |
435 | | uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, |
436 | | bool aLineBreakBefore, gfxFloat aWidth, |
437 | | PropertyProvider *aProvider, |
438 | | SuppressBreak aSuppressBreak, |
439 | | gfxFloat *aTrimWhitespace, |
440 | | bool aHangWhitespace, |
441 | | Metrics *aMetrics, |
442 | | gfxFont::BoundingBoxType aBoundingBoxType, |
443 | | DrawTarget* aDrawTargetForTightBoundingBox, |
444 | | bool *aUsedHyphenation, |
445 | | uint32_t *aLastBreak, |
446 | | bool aCanWordWrap, |
447 | | gfxBreakPriority *aBreakPriority); |
448 | | |
449 | | // Utility getters |
450 | | |
451 | 0 | void *GetUserData() const { return mUserData; } |
452 | 0 | void SetUserData(void *aUserData) { mUserData = aUserData; } |
453 | | |
454 | 0 | void SetFlagBits(nsTextFrameUtils::Flags aFlags) { |
455 | 0 | mFlags2 |= aFlags; |
456 | 0 | } |
457 | 0 | void ClearFlagBits(nsTextFrameUtils::Flags aFlags) { |
458 | 0 | mFlags2 &= ~aFlags; |
459 | 0 | } |
460 | 0 | const gfxSkipChars& GetSkipChars() const { return mSkipChars; } |
461 | 0 | gfxFontGroup *GetFontGroup() const { return mFontGroup; } |
462 | | |
463 | | |
464 | | // Call this, don't call "new gfxTextRun" directly. This does custom |
465 | | // allocation and initialization |
466 | | static already_AddRefed<gfxTextRun> |
467 | | Create(const gfxTextRunFactory::Parameters *aParams, |
468 | | uint32_t aLength, gfxFontGroup *aFontGroup, |
469 | | mozilla::gfx::ShapedTextFlags aFlags, |
470 | | nsTextFrameUtils::Flags aFlags2); |
471 | | |
472 | | // The text is divided into GlyphRuns as necessary. (In the vast majority |
473 | | // of cases, a gfxTextRun contains just a single GlyphRun.) |
474 | | struct GlyphRun { |
475 | | RefPtr<gfxFont> mFont; // never null in a valid GlyphRun |
476 | | uint32_t mCharacterOffset; // into original UTF16 string |
477 | | mozilla::gfx::ShapedTextFlags mOrientation; // gfxTextRunFactory::TEXT_ORIENT_* value |
478 | | gfxTextRange::MatchType mMatchType; |
479 | | }; |
480 | | |
481 | | class MOZ_STACK_CLASS GlyphRunIterator { |
482 | | public: |
483 | | GlyphRunIterator(const gfxTextRun *aTextRun, Range aRange) |
484 | | : mTextRun(aTextRun) |
485 | | , mStartOffset(aRange.start) |
486 | | , mEndOffset(aRange.end) { |
487 | | mNextIndex = mTextRun->FindFirstGlyphRunContaining(aRange.start); |
488 | | } |
489 | | bool NextRun(); |
490 | | const GlyphRun *GetGlyphRun() const { return mGlyphRun; } |
491 | | uint32_t GetStringStart() const { return mStringStart; } |
492 | | uint32_t GetStringEnd() const { return mStringEnd; } |
493 | | private: |
494 | | const gfxTextRun *mTextRun; |
495 | | MOZ_INIT_OUTSIDE_CTOR const GlyphRun *mGlyphRun; |
496 | | MOZ_INIT_OUTSIDE_CTOR uint32_t mStringStart; |
497 | | MOZ_INIT_OUTSIDE_CTOR uint32_t mStringEnd; |
498 | | uint32_t mNextIndex; |
499 | | uint32_t mStartOffset; |
500 | | uint32_t mEndOffset; |
501 | | }; |
502 | | |
503 | | class GlyphRunOffsetComparator { |
504 | | public: |
505 | | bool Equals(const GlyphRun& a, |
506 | | const GlyphRun& b) const |
507 | | { |
508 | | return a.mCharacterOffset == b.mCharacterOffset; |
509 | | } |
510 | | |
511 | | bool LessThan(const GlyphRun& a, |
512 | | const GlyphRun& b) const |
513 | | { |
514 | | return a.mCharacterOffset < b.mCharacterOffset; |
515 | | } |
516 | | }; |
517 | | |
518 | | friend class GlyphRunIterator; |
519 | | friend class FontSelector; |
520 | | |
521 | | // API for setting up the textrun glyphs. Should only be called by |
522 | | // things that construct textruns. |
523 | | /** |
524 | | * We've found a run of text that should use a particular font. Call this |
525 | | * only during initialization when font substitution has been computed. |
526 | | * Call it before setting up the glyphs for the characters in this run; |
527 | | * SetMissingGlyph requires that the correct glyphrun be installed. |
528 | | * |
529 | | * If aForceNewRun, a new glyph run will be added, even if the |
530 | | * previously added run uses the same font. If glyph runs are |
531 | | * added out of strictly increasing aStartCharIndex order (via |
532 | | * force), then SortGlyphRuns must be called after all glyph runs |
533 | | * are added before any further operations are performed with this |
534 | | * TextRun. |
535 | | */ |
536 | | nsresult AddGlyphRun(gfxFont *aFont, gfxTextRange::MatchType aMatchType, |
537 | | uint32_t aStartCharIndex, bool aForceNewRun, |
538 | | mozilla::gfx::ShapedTextFlags aOrientation); |
539 | | void ResetGlyphRuns() |
540 | | { |
541 | | if (mHasGlyphRunArray) { |
542 | | MOZ_ASSERT(mGlyphRunArray.Length() > 1); |
543 | | // Discard all but the first GlyphRun... |
544 | | mGlyphRunArray.TruncateLength(1); |
545 | | // ...and then convert to the single-run representation. |
546 | | ConvertFromGlyphRunArray(); |
547 | | } |
548 | | // Clear out the one remaining GlyphRun. |
549 | | mSingleGlyphRun.mFont = nullptr; |
550 | | } |
551 | | void SortGlyphRuns(); |
552 | | void SanitizeGlyphRuns(); |
553 | | |
554 | 0 | const CompressedGlyph* GetCharacterGlyphs() const final { |
555 | 0 | MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs"); |
556 | 0 | return mCharacterGlyphs; |
557 | 0 | } |
558 | | CompressedGlyph* GetCharacterGlyphs() final { |
559 | | MOZ_ASSERT(mCharacterGlyphs, "failed to initialize mCharacterGlyphs"); |
560 | | return mCharacterGlyphs; |
561 | | } |
562 | | |
563 | | // clean out results from shaping in progress, used for fallback scenarios |
564 | | void ClearGlyphsAndCharacters(); |
565 | | |
566 | | void SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget, |
567 | | uint32_t aCharIndex, |
568 | | mozilla::gfx::ShapedTextFlags aOrientation); |
569 | | |
570 | | // Set the glyph data for the given character index to the font's |
571 | | // space glyph, IF this can be done as a "simple" glyph record |
572 | | // (not requiring a DetailedGlyph entry). This avoids the need to call |
573 | | // the font shaper and go through the shaped-word cache for most spaces. |
574 | | // |
575 | | // The parameter aSpaceChar is the original character code for which |
576 | | // this space glyph is being used; if this is U+0020, we need to record |
577 | | // that it could be trimmed at a run edge, whereas other kinds of space |
578 | | // (currently just U+00A0) would not be trimmable/breakable. |
579 | | // |
580 | | // Returns true if it was able to set simple glyph data for the space; |
581 | | // if it returns false, the caller needs to fall back to some other |
582 | | // means to create the necessary (detailed) glyph data. |
583 | | bool SetSpaceGlyphIfSimple(gfxFont *aFont, uint32_t aCharIndex, |
584 | | char16_t aSpaceChar, |
585 | | mozilla::gfx::ShapedTextFlags aOrientation); |
586 | | |
587 | | // Record the positions of specific characters that layout may need to |
588 | | // detect in the textrun, even though it doesn't have an explicit copy |
589 | | // of the original text. These are recorded using flag bits in the |
590 | | // CompressedGlyph record; if necessary, we convert "simple" glyph records |
591 | | // to "complex" ones as the Tab and Newline flags are not present in |
592 | | // simple CompressedGlyph records. |
593 | 0 | void SetIsTab(uint32_t aIndex) { |
594 | 0 | EnsureComplexGlyph(aIndex).SetIsTab(); |
595 | 0 | } |
596 | 0 | void SetIsNewline(uint32_t aIndex) { |
597 | 0 | EnsureComplexGlyph(aIndex).SetIsNewline(); |
598 | 0 | } |
599 | 0 | void SetNoEmphasisMark(uint32_t aIndex) { |
600 | 0 | EnsureComplexGlyph(aIndex).SetNoEmphasisMark(); |
601 | 0 | } |
602 | 0 | void SetIsFormattingControl(uint32_t aIndex) { |
603 | 0 | EnsureComplexGlyph(aIndex).SetIsFormattingControl(); |
604 | 0 | } |
605 | | |
606 | | /** |
607 | | * Prefetch all the glyph extents needed to ensure that Measure calls |
608 | | * on this textrun not requesting tight boundingBoxes will succeed. Note |
609 | | * that some glyph extents might not be fetched due to OOM or other |
610 | | * errors. |
611 | | */ |
612 | | void FetchGlyphExtents(DrawTarget* aRefDrawTarget); |
613 | | |
614 | | uint32_t CountMissingGlyphs() const; |
615 | | |
616 | | const GlyphRun* GetGlyphRuns(uint32_t* aNumGlyphRuns) const |
617 | | { |
618 | | if (mHasGlyphRunArray) { |
619 | | *aNumGlyphRuns = mGlyphRunArray.Length(); |
620 | | return mGlyphRunArray.Elements(); |
621 | | } else { |
622 | | *aNumGlyphRuns = mSingleGlyphRun.mFont ? 1 : 0; |
623 | | return &mSingleGlyphRun; |
624 | | } |
625 | | } |
626 | | // Returns the index of the GlyphRun containing the given offset. |
627 | | // Returns mGlyphRuns.Length() when aOffset is mCharacterCount. |
628 | | uint32_t FindFirstGlyphRunContaining(uint32_t aOffset) const; |
629 | | |
630 | | // Copy glyph data from a ShapedWord into this textrun. |
631 | | void CopyGlyphDataFrom(gfxShapedWord *aSource, uint32_t aStart); |
632 | | |
633 | | // Copy glyph data for a range of characters from aSource to this |
634 | | // textrun. |
635 | | void CopyGlyphDataFrom(gfxTextRun *aSource, Range aRange, uint32_t aDest); |
636 | | |
637 | | // Tell the textrun to release its reference to its creating gfxFontGroup |
638 | | // immediately, rather than on destruction. This is used for textruns |
639 | | // that are actually owned by a gfxFontGroup, so that they don't keep it |
640 | | // permanently alive due to a circular reference. (The caller of this is |
641 | | // taking responsibility for ensuring the textrun will not outlive its |
642 | | // mFontGroup.) |
643 | | void ReleaseFontGroup(); |
644 | | |
645 | | struct LigatureData { |
646 | | // textrun range of the containing ligature |
647 | | Range mRange; |
648 | | // appunits advance to the start of the ligature part within the ligature; |
649 | | // never includes any spacing |
650 | | gfxFloat mPartAdvance; |
651 | | // appunits width of the ligature part; includes before-spacing |
652 | | // when the part is at the start of the ligature, and after-spacing |
653 | | // when the part is as the end of the ligature |
654 | | gfxFloat mPartWidth; |
655 | | |
656 | | bool mClipBeforePart; |
657 | | bool mClipAfterPart; |
658 | | }; |
659 | | |
660 | | // return storage used by this run, for memory reporter; |
661 | | // nsTransformedTextRun needs to override this as it holds additional data |
662 | | virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
663 | | MOZ_MUST_OVERRIDE; |
664 | | virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) |
665 | | MOZ_MUST_OVERRIDE; |
666 | | |
667 | 0 | nsTextFrameUtils::Flags GetFlags2() const { |
668 | 0 | return mFlags2; |
669 | 0 | } |
670 | | |
671 | | // Get the size, if it hasn't already been gotten, marking as it goes. |
672 | 0 | size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { |
673 | 0 | if (mFlags2 & nsTextFrameUtils::Flags::TEXT_RUN_SIZE_ACCOUNTED) { |
674 | 0 | return 0; |
675 | 0 | } |
676 | 0 | mFlags2 |= nsTextFrameUtils::Flags::TEXT_RUN_SIZE_ACCOUNTED; |
677 | 0 | return SizeOfIncludingThis(aMallocSizeOf); |
678 | 0 | } |
679 | 0 | void ResetSizeOfAccountingFlags() { |
680 | 0 | mFlags2 &= ~nsTextFrameUtils::Flags::TEXT_RUN_SIZE_ACCOUNTED; |
681 | 0 | } |
682 | | |
683 | | // shaping state - for some font features, fallback is required that |
684 | | // affects the entire run. for example, fallback for one script/font |
685 | | // portion of a textrun requires fallback to be applied to the entire run |
686 | | |
687 | | enum ShapingState : uint8_t { |
688 | | eShapingState_Normal, // default state |
689 | | eShapingState_ShapingWithFeature, // have shaped with feature |
690 | | eShapingState_ShapingWithFallback, // have shaped with fallback |
691 | | eShapingState_Aborted, // abort initial iteration |
692 | | eShapingState_ForceFallbackFeature // redo with fallback forced on |
693 | | }; |
694 | | |
695 | | ShapingState GetShapingState() const { return mShapingState; } |
696 | | void SetShapingState(ShapingState aShapingState) { |
697 | | mShapingState = aShapingState; |
698 | | } |
699 | | |
700 | | int32_t GetAdvanceForGlyph(uint32_t aIndex) const |
701 | 0 | { |
702 | 0 | const CompressedGlyph& glyphData = mCharacterGlyphs[aIndex]; |
703 | 0 | if (glyphData.IsSimpleGlyph()) { |
704 | 0 | return glyphData.GetSimpleAdvance(); |
705 | 0 | } |
706 | 0 | uint32_t glyphCount = glyphData.GetGlyphCount(); |
707 | 0 | if (!glyphCount) { |
708 | 0 | return 0; |
709 | 0 | } |
710 | 0 | const DetailedGlyph* details = GetDetailedGlyphs(aIndex); |
711 | 0 | int32_t advance = 0; |
712 | 0 | for (uint32_t j = 0; j < glyphCount; ++j, ++details) { |
713 | 0 | advance += details->mAdvance; |
714 | 0 | } |
715 | 0 | return advance; |
716 | 0 | } |
717 | | |
718 | | #ifdef DEBUG |
719 | | void Dump(FILE* aOutput); |
720 | | #endif |
721 | | |
722 | | protected: |
723 | | /** |
724 | | * Create a textrun, and set its mCharacterGlyphs to point immediately |
725 | | * after the base object; this is ONLY used in conjunction with placement |
726 | | * new, after allocating a block large enough for the glyph records to |
727 | | * follow the base textrun object. |
728 | | */ |
729 | | gfxTextRun(const gfxTextRunFactory::Parameters *aParams, |
730 | | uint32_t aLength, gfxFontGroup *aFontGroup, |
731 | | mozilla::gfx::ShapedTextFlags aFlags, |
732 | | nsTextFrameUtils::Flags aFlags2); |
733 | | |
734 | | /** |
735 | | * Helper for the Create() factory method to allocate the required |
736 | | * glyph storage for a textrun object with the basic size aSize, |
737 | | * plus room for aLength glyph records. |
738 | | */ |
739 | | static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength); |
740 | | |
741 | | // Pointer to the array of CompressedGlyph records; must be initialized |
742 | | // when the object is constructed. |
743 | | CompressedGlyph *mCharacterGlyphs; |
744 | | |
745 | | private: |
746 | | // **** general helpers **** |
747 | | |
748 | | // Get the total advance for a range of glyphs. |
749 | | int32_t GetAdvanceForGlyphs(Range aRange) const; |
750 | | |
751 | | // Spacing for characters outside the range aSpacingStart/aSpacingEnd |
752 | | // is assumed to be zero; such characters are not passed to aProvider. |
753 | | // This is useful to protect aProvider from being passed character indices |
754 | | // it is not currently able to handle. |
755 | | bool GetAdjustedSpacingArray(Range aRange, PropertyProvider *aProvider, |
756 | | Range aSpacingRange, |
757 | | nsTArray<PropertyProvider::Spacing>* |
758 | | aSpacing) const; |
759 | | |
760 | | CompressedGlyph& EnsureComplexGlyph(uint32_t aIndex) |
761 | 0 | { |
762 | 0 | gfxShapedText::EnsureComplexGlyph(aIndex, mCharacterGlyphs[aIndex]); |
763 | 0 | return mCharacterGlyphs[aIndex]; |
764 | 0 | } |
765 | | |
766 | | // **** ligature helpers **** |
767 | | // (Platforms do the actual ligaturization, but we need to do a bunch of stuff |
768 | | // to handle requests that begin or end inside a ligature) |
769 | | |
770 | | // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero |
771 | | LigatureData ComputeLigatureData(Range aPartRange, |
772 | | PropertyProvider *aProvider) const; |
773 | | gfxFloat ComputePartialLigatureWidth(Range aPartRange, |
774 | | PropertyProvider *aProvider) const; |
775 | | void DrawPartialLigature(gfxFont* aFont, Range aRange, |
776 | | mozilla::gfx::Point* aPt, |
777 | | PropertyProvider* aProvider, |
778 | | TextRunDrawParams& aParams, |
779 | | mozilla::gfx::ShapedTextFlags aOrientation) const; |
780 | | // Advance aRange.start to the start of the nearest ligature, back |
781 | | // up aRange.end to the nearest ligature end; may result in |
782 | | // aRange->start == aRange->end. |
783 | | void ShrinkToLigatureBoundaries(Range* aRange) const; |
784 | | // result in appunits |
785 | | gfxFloat GetPartialLigatureWidth(Range aRange, |
786 | | PropertyProvider *aProvider) const; |
787 | | void AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange, |
788 | | gfxFont::BoundingBoxType aBoundingBoxType, |
789 | | DrawTarget* aRefDrawTarget, |
790 | | PropertyProvider *aProvider, |
791 | | mozilla::gfx::ShapedTextFlags aOrientation, |
792 | | Metrics *aMetrics) const; |
793 | | |
794 | | // **** measurement helper **** |
795 | | void AccumulateMetricsForRun(gfxFont *aFont, Range aRange, |
796 | | gfxFont::BoundingBoxType aBoundingBoxType, |
797 | | DrawTarget* aRefDrawTarget, |
798 | | PropertyProvider *aProvider, |
799 | | Range aSpacingRange, |
800 | | mozilla::gfx::ShapedTextFlags aOrientation, |
801 | | Metrics *aMetrics) const; |
802 | | |
803 | | // **** drawing helper **** |
804 | | void DrawGlyphs(gfxFont* aFont, Range aRange, mozilla::gfx::Point* aPt, |
805 | | PropertyProvider* aProvider, Range aSpacingRange, |
806 | | TextRunDrawParams& aParams, |
807 | | mozilla::gfx::ShapedTextFlags aOrientation) const; |
808 | | |
809 | | // The textrun holds either a single GlyphRun -or- an array; |
810 | | // the flag mHasGlyphRunArray tells us which is present. |
811 | | union { |
812 | | GlyphRun mSingleGlyphRun; |
813 | | nsTArray<GlyphRun> mGlyphRunArray; |
814 | | }; |
815 | | |
816 | | void ConvertToGlyphRunArray() { |
817 | | MOZ_ASSERT(!mHasGlyphRunArray && mSingleGlyphRun.mFont); |
818 | | GlyphRun tmp = std::move(mSingleGlyphRun); |
819 | | mSingleGlyphRun.~GlyphRun(); |
820 | | new (&mGlyphRunArray) nsTArray<GlyphRun>(2); |
821 | | mGlyphRunArray.AppendElement(std::move(tmp)); |
822 | | mHasGlyphRunArray = true; |
823 | | } |
824 | | |
825 | | void ConvertFromGlyphRunArray() { |
826 | | MOZ_ASSERT(mHasGlyphRunArray && mGlyphRunArray.Length() == 1); |
827 | | GlyphRun tmp = std::move(mGlyphRunArray[0]); |
828 | | mGlyphRunArray.~nsTArray<GlyphRun>(); |
829 | | new (&mSingleGlyphRun) GlyphRun(std::move(tmp)); |
830 | | mHasGlyphRunArray = false; |
831 | | } |
832 | | |
833 | | void *mUserData; |
834 | | |
835 | | // mFontGroup is usually a strong reference, but refcounting is managed |
836 | | // manually because it may be explicitly released by ReleaseFontGroup() |
837 | | // in the case where the font group actually owns the textrun. |
838 | | gfxFontGroup* MOZ_OWNING_REF mFontGroup; |
839 | | |
840 | | gfxSkipChars mSkipChars; |
841 | | |
842 | | nsTextFrameUtils::Flags mFlags2; // additional flags (see also gfxShapedText::mFlags) |
843 | | |
844 | | bool mSkipDrawing; // true if the font group we used had a user font |
845 | | // download that's in progress, so we should hide text |
846 | | // until the download completes (or timeout fires) |
847 | | bool mReleasedFontGroup; // we already called NS_RELEASE on |
848 | | // mFontGroup, so don't do it again |
849 | | bool mHasGlyphRunArray; // whether we're using an array or |
850 | | // just storing a single glyphrun |
851 | | |
852 | | // shaping state for handling variant fallback features |
853 | | // such as subscript/superscript variant glyphs |
854 | | ShapingState mShapingState; |
855 | | }; |
856 | | |
857 | | class gfxFontGroup final : public gfxTextRunFactory { |
858 | | public: |
859 | | typedef mozilla::unicode::Script Script; |
860 | | typedef gfxShapedText::CompressedGlyph CompressedGlyph; |
861 | | |
862 | | static void Shutdown(); // platform must call this to release the languageAtomService |
863 | | |
864 | | gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList, |
865 | | const gfxFontStyle* aStyle, |
866 | | gfxTextPerfMetrics* aTextPerf, |
867 | | gfxUserFontSet* aUserFontSet, |
868 | | gfxFloat aDevToCssSize); |
869 | | |
870 | | virtual ~gfxFontGroup(); |
871 | | |
872 | | // Returns first valid font in the fontlist or default font. |
873 | | // Initiates userfont loads if userfont not loaded. |
874 | | // aGeneric: if non-null, returns the CSS generic type that was mapped to |
875 | | // this font |
876 | | gfxFont* GetFirstValidFont(uint32_t aCh = 0x20, |
877 | | mozilla::FontFamilyType* aGeneric = nullptr); |
878 | | |
879 | | // Returns the first font in the font-group that has an OpenType MATH table, |
880 | | // or null if no such font is available. The GetMathConstant methods may be |
881 | | // called on the returned font. |
882 | | gfxFont *GetFirstMathFont(); |
883 | | |
884 | | const gfxFontStyle *GetStyle() const { return &mStyle; } |
885 | | |
886 | | gfxFontGroup *Copy(const gfxFontStyle *aStyle); |
887 | | |
888 | | /** |
889 | | * The listed characters should be treated as invisible and zero-width |
890 | | * when creating textruns. |
891 | | */ |
892 | | static bool IsInvalidChar(uint8_t ch); |
893 | | static bool IsInvalidChar(char16_t ch); |
894 | | |
895 | | /** |
896 | | * Make a textrun for a given string. |
897 | | * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the |
898 | | * textrun will copy it. |
899 | | * This calls FetchGlyphExtents on the textrun. |
900 | | */ |
901 | | already_AddRefed<gfxTextRun> |
902 | | MakeTextRun(const char16_t *aString, uint32_t aLength, |
903 | | const Parameters *aParams, |
904 | | mozilla::gfx::ShapedTextFlags aFlags, |
905 | | nsTextFrameUtils::Flags aFlags2, |
906 | | gfxMissingFontRecorder *aMFR); |
907 | | /** |
908 | | * Make a textrun for a given string. |
909 | | * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the |
910 | | * textrun will copy it. |
911 | | * This calls FetchGlyphExtents on the textrun. |
912 | | */ |
913 | | already_AddRefed<gfxTextRun> |
914 | | MakeTextRun(const uint8_t *aString, uint32_t aLength, |
915 | | const Parameters *aParams, |
916 | | mozilla::gfx::ShapedTextFlags aFlags, |
917 | | nsTextFrameUtils::Flags aFlags2, |
918 | | gfxMissingFontRecorder *aMFR); |
919 | | |
920 | | /** |
921 | | * Textrun creation helper for clients that don't want to pass |
922 | | * a full Parameters record. |
923 | | */ |
924 | | template<typename T> |
925 | | already_AddRefed<gfxTextRun> |
926 | | MakeTextRun(const T* aString, uint32_t aLength, |
927 | | DrawTarget* aRefDrawTarget, |
928 | | int32_t aAppUnitsPerDevUnit, |
929 | | mozilla::gfx::ShapedTextFlags aFlags, |
930 | | nsTextFrameUtils::Flags aFlags2, |
931 | | gfxMissingFontRecorder *aMFR) |
932 | 0 | { |
933 | 0 | gfxTextRunFactory::Parameters params = { |
934 | 0 | aRefDrawTarget, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit |
935 | 0 | }; |
936 | 0 | return MakeTextRun(aString, aLength, ¶ms, aFlags, aFlags2, aMFR); |
937 | 0 | } Unexecuted instantiation: already_AddRefed<gfxTextRun> gfxFontGroup::MakeTextRun<unsigned char>(unsigned char const*, unsigned int, mozilla::gfx::DrawTarget*, int, mozilla::gfx::ShapedTextFlags, nsTextFrameUtils::Flags, gfxMissingFontRecorder*) Unexecuted instantiation: already_AddRefed<gfxTextRun> gfxFontGroup::MakeTextRun<char16_t>(char16_t const*, unsigned int, mozilla::gfx::DrawTarget*, int, mozilla::gfx::ShapedTextFlags, nsTextFrameUtils::Flags, gfxMissingFontRecorder*) |
938 | | |
939 | | // Get the (possibly-cached) width of the hyphen character. |
940 | | gfxFloat GetHyphenWidth(const gfxTextRun::PropertyProvider* aProvider); |
941 | | |
942 | | /** |
943 | | * Make a text run representing a single hyphen character. |
944 | | * This will use U+2010 HYPHEN if available in the first font, |
945 | | * otherwise fall back to U+002D HYPHEN-MINUS. |
946 | | * The caller is responsible for deleting the returned text run |
947 | | * when no longer required. |
948 | | */ |
949 | | already_AddRefed<gfxTextRun> |
950 | | MakeHyphenTextRun(DrawTarget* aDrawTarget, uint32_t aAppUnitsPerDevUnit); |
951 | | |
952 | | /** |
953 | | * Check whether a given font (specified by its gfxFontEntry) |
954 | | * is already in the fontgroup's list of actual fonts |
955 | | */ |
956 | | bool HasFont(const gfxFontEntry *aFontEntry); |
957 | | |
958 | | // This returns the preferred underline for this font group. |
959 | | // Some CJK fonts have wrong underline offset in its metrics. |
960 | | // If this group has such "bad" font, each platform's gfxFontGroup |
961 | | // initialized mUnderlineOffset. The value should be lower value of |
962 | | // first font's metrics and the bad font's metrics. Otherwise, this |
963 | | // returns from first font's metrics. |
964 | | enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX }; |
965 | | gfxFloat GetUnderlineOffset(); |
966 | | |
967 | | gfxFont* FindFontForChar(uint32_t ch, uint32_t prevCh, uint32_t aNextCh, |
968 | | Script aRunScript, gfxFont *aPrevMatchedFont, |
969 | | gfxTextRange::MatchType *aMatchType); |
970 | | |
971 | | gfxUserFontSet* GetUserFontSet(); |
972 | | |
973 | | // With downloadable fonts, the composition of the font group can change as fonts are downloaded |
974 | | // for each change in state of the user font set, the generation value is bumped to avoid picking up |
975 | | // previously created text runs in the text run word cache. For font groups based on stylesheets |
976 | | // with no @font-face rule, this always returns 0. |
977 | | uint64_t GetGeneration(); |
978 | | |
979 | | // generation of the latest fontset rebuild, 0 when no fontset present |
980 | | uint64_t GetRebuildGeneration(); |
981 | | |
982 | | // used when logging text performance |
983 | 0 | gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; } |
984 | | |
985 | | // This will call UpdateUserFonts() if the user font set is changed. |
986 | | void SetUserFontSet(gfxUserFontSet *aUserFontSet); |
987 | | |
988 | | void ClearCachedData() |
989 | | { |
990 | | mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET; |
991 | | mSkipDrawing = false; |
992 | | mHyphenWidth = -1; |
993 | | mCachedEllipsisTextRun = nullptr; |
994 | | } |
995 | | |
996 | | // If there is a user font set, check to see whether the font list or any |
997 | | // caches need updating. |
998 | | void UpdateUserFonts(); |
999 | | |
1000 | | // search for a specific userfont in the list of fonts |
1001 | | bool ContainsUserFont(const gfxUserFontEntry* aUserFont); |
1002 | | |
1003 | | bool ShouldSkipDrawing() const { |
1004 | | return mSkipDrawing; |
1005 | | } |
1006 | | |
1007 | | class LazyReferenceDrawTargetGetter { |
1008 | | public: |
1009 | | virtual already_AddRefed<DrawTarget> GetRefDrawTarget() = 0; |
1010 | | }; |
1011 | | // The gfxFontGroup keeps ownership of this textrun. |
1012 | | // It is only guaranteed to exist until the next call to GetEllipsisTextRun |
1013 | | // (which might use a different appUnitsPerDev value or flags) for the font |
1014 | | // group, or until UpdateUserFonts is called, or the fontgroup is destroyed. |
1015 | | // Get it/use it/forget it :) - don't keep a reference that might go stale. |
1016 | | gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, |
1017 | | mozilla::gfx::ShapedTextFlags aFlags, |
1018 | | LazyReferenceDrawTargetGetter& aRefDrawTargetGetter); |
1019 | | |
1020 | | protected: |
1021 | | // search through pref fonts for a character, return nullptr if no matching pref font |
1022 | | gfxFont* WhichPrefFontSupportsChar(uint32_t aCh, |
1023 | | uint32_t aNextCh); |
1024 | | |
1025 | | gfxFont* WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh, |
1026 | | Script aRunScript); |
1027 | | |
1028 | | template<typename T> |
1029 | | void ComputeRanges(nsTArray<gfxTextRange>& mRanges, |
1030 | | const T *aString, uint32_t aLength, |
1031 | | Script aRunScript, |
1032 | | mozilla::gfx::ShapedTextFlags aOrientation); |
1033 | | |
1034 | | class FamilyFace { |
1035 | | public: |
1036 | | FamilyFace() : mFamily(nullptr), mFontEntry(nullptr), |
1037 | | mGeneric(mozilla::eFamily_none), |
1038 | | mFontCreated(false), |
1039 | | mLoading(false), mInvalid(false), |
1040 | | mCheckForFallbackFaces(false) |
1041 | 0 | { } |
1042 | | |
1043 | | FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont, |
1044 | | mozilla::FontFamilyType aGeneric) |
1045 | | : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(true), |
1046 | | mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) |
1047 | 0 | { |
1048 | 0 | NS_ASSERTION(aFont, "font pointer must not be null"); |
1049 | 0 | NS_ASSERTION(!aFamily || |
1050 | 0 | aFamily->ContainsFace(aFont->GetFontEntry()), |
1051 | 0 | "font is not a member of the given family"); |
1052 | 0 | mFont = aFont; |
1053 | 0 | NS_ADDREF(aFont); |
1054 | 0 | } |
1055 | | |
1056 | | FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry, |
1057 | | mozilla::FontFamilyType aGeneric) |
1058 | | : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(false), |
1059 | | mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) |
1060 | | { |
1061 | | NS_ASSERTION(aFontEntry, "font entry pointer must not be null"); |
1062 | | NS_ASSERTION(!aFamily || |
1063 | | aFamily->ContainsFace(aFontEntry), |
1064 | | "font is not a member of the given family"); |
1065 | | mFontEntry = aFontEntry; |
1066 | | NS_ADDREF(aFontEntry); |
1067 | | } |
1068 | | |
1069 | | FamilyFace(const FamilyFace& aOtherFamilyFace) |
1070 | | : mFamily(aOtherFamilyFace.mFamily), |
1071 | | mGeneric(aOtherFamilyFace.mGeneric), |
1072 | | mFontCreated(aOtherFamilyFace.mFontCreated), |
1073 | | mLoading(aOtherFamilyFace.mLoading), |
1074 | | mInvalid(aOtherFamilyFace.mInvalid), |
1075 | | mCheckForFallbackFaces(aOtherFamilyFace.mCheckForFallbackFaces) |
1076 | | { |
1077 | | if (mFontCreated) { |
1078 | | mFont = aOtherFamilyFace.mFont; |
1079 | | NS_ADDREF(mFont); |
1080 | | } else { |
1081 | | mFontEntry = aOtherFamilyFace.mFontEntry; |
1082 | | NS_IF_ADDREF(mFontEntry); |
1083 | | } |
1084 | | } |
1085 | | |
1086 | | ~FamilyFace() |
1087 | | { |
1088 | | if (mFontCreated) { |
1089 | | NS_RELEASE(mFont); |
1090 | | } else { |
1091 | | NS_IF_RELEASE(mFontEntry); |
1092 | | } |
1093 | | } |
1094 | | |
1095 | | FamilyFace& operator=(const FamilyFace& aOther) |
1096 | 0 | { |
1097 | 0 | if (mFontCreated) { |
1098 | 0 | NS_RELEASE(mFont); |
1099 | 0 | } else { |
1100 | 0 | NS_IF_RELEASE(mFontEntry); |
1101 | 0 | } |
1102 | 0 |
|
1103 | 0 | mFamily = aOther.mFamily; |
1104 | 0 | mGeneric = aOther.mGeneric; |
1105 | 0 | mFontCreated = aOther.mFontCreated; |
1106 | 0 | mLoading = aOther.mLoading; |
1107 | 0 | mInvalid = aOther.mInvalid; |
1108 | 0 |
|
1109 | 0 | if (mFontCreated) { |
1110 | 0 | mFont = aOther.mFont; |
1111 | 0 | NS_ADDREF(mFont); |
1112 | 0 | } else { |
1113 | 0 | mFontEntry = aOther.mFontEntry; |
1114 | 0 | NS_IF_ADDREF(mFontEntry); |
1115 | 0 | } |
1116 | 0 |
|
1117 | 0 | return *this; |
1118 | 0 | } |
1119 | | |
1120 | | gfxFontFamily* Family() const { return mFamily.get(); } |
1121 | | gfxFont* Font() const { |
1122 | | return mFontCreated ? mFont : nullptr; |
1123 | | } |
1124 | | |
1125 | | gfxFontEntry* FontEntry() const { |
1126 | | return mFontCreated ? mFont->GetFontEntry() : mFontEntry; |
1127 | | } |
1128 | | |
1129 | | mozilla::FontFamilyType Generic() const { return mGeneric; } |
1130 | | |
1131 | | bool IsUserFontContainer() const { |
1132 | | return FontEntry()->mIsUserFontContainer; |
1133 | | } |
1134 | | bool IsLoading() const { return mLoading; } |
1135 | | bool IsInvalid() const { return mInvalid; } |
1136 | | void CheckState(bool& aSkipDrawing); |
1137 | | void SetLoading(bool aIsLoading) { mLoading = aIsLoading; } |
1138 | | void SetInvalid() { mInvalid = true; } |
1139 | | bool CheckForFallbackFaces() const { return mCheckForFallbackFaces; } |
1140 | | void SetCheckForFallbackFaces() { mCheckForFallbackFaces = true; } |
1141 | | |
1142 | | void SetFont(gfxFont* aFont) |
1143 | | { |
1144 | | NS_ASSERTION(aFont, "font pointer must not be null"); |
1145 | | NS_ADDREF(aFont); |
1146 | | if (mFontCreated) { |
1147 | | NS_RELEASE(mFont); |
1148 | | } else { |
1149 | | NS_IF_RELEASE(mFontEntry); |
1150 | | } |
1151 | | mFont = aFont; |
1152 | | mFontCreated = true; |
1153 | | mLoading = false; |
1154 | | } |
1155 | | |
1156 | | bool EqualsUserFont(const gfxUserFontEntry* aUserFont) const; |
1157 | | |
1158 | | private: |
1159 | | RefPtr<gfxFontFamily> mFamily; |
1160 | | // either a font or a font entry exists |
1161 | | union { |
1162 | | // Whichever of these fields is actually present will be a strong |
1163 | | // reference, with refcounting handled manually. |
1164 | | gfxFont* MOZ_OWNING_REF mFont; |
1165 | | gfxFontEntry* MOZ_OWNING_REF mFontEntry; |
1166 | | }; |
1167 | | mozilla::FontFamilyType mGeneric; |
1168 | | bool mFontCreated : 1; |
1169 | | bool mLoading : 1; |
1170 | | bool mInvalid : 1; |
1171 | | bool mCheckForFallbackFaces : 1; |
1172 | | }; |
1173 | | |
1174 | | // List of font families, either named or generic. |
1175 | | // Generic names map to system pref fonts based on language. |
1176 | | mozilla::FontFamilyList mFamilyList; |
1177 | | |
1178 | | // Fontlist containing a font entry for each family found. gfxFont objects |
1179 | | // are created as needed and userfont loads are initiated when needed. |
1180 | | // Code should be careful about addressing this array directly. |
1181 | | nsTArray<FamilyFace> mFonts; |
1182 | | |
1183 | | RefPtr<gfxFont> mDefaultFont; |
1184 | | gfxFontStyle mStyle; |
1185 | | |
1186 | | gfxFloat mUnderlineOffset; |
1187 | | gfxFloat mHyphenWidth; |
1188 | | gfxFloat mDevToCssSize; |
1189 | | |
1190 | | RefPtr<gfxUserFontSet> mUserFontSet; |
1191 | | uint64_t mCurrGeneration; // track the current user font set generation, rebuild font list if needed |
1192 | | |
1193 | | gfxTextPerfMetrics *mTextPerf; |
1194 | | |
1195 | | // Cache a textrun representing an ellipsis (useful for CSS text-overflow) |
1196 | | // at a specific appUnitsPerDevPixel size and orientation |
1197 | | RefPtr<gfxTextRun> mCachedEllipsisTextRun; |
1198 | | |
1199 | | // cache the most recent pref font to avoid general pref font lookup |
1200 | | RefPtr<gfxFontFamily> mLastPrefFamily; |
1201 | | RefPtr<gfxFont> mLastPrefFont; |
1202 | | eFontPrefLang mLastPrefLang; // lang group for last pref font |
1203 | | eFontPrefLang mPageLang; |
1204 | | bool mLastPrefFirstFont; // is this the first font in the list of pref fonts for this lang group? |
1205 | | |
1206 | | bool mSkipDrawing; // hide text while waiting for a font |
1207 | | // download to complete (or fallback |
1208 | | // timer to fire) |
1209 | | |
1210 | | /** |
1211 | | * Textrun creation short-cuts for special cases where we don't need to |
1212 | | * call a font shaper to generate glyphs. |
1213 | | */ |
1214 | | already_AddRefed<gfxTextRun> |
1215 | | MakeEmptyTextRun(const Parameters *aParams, |
1216 | | mozilla::gfx::ShapedTextFlags aFlags, |
1217 | | nsTextFrameUtils::Flags aFlags2); |
1218 | | |
1219 | | already_AddRefed<gfxTextRun> |
1220 | | MakeSpaceTextRun(const Parameters *aParams, |
1221 | | mozilla::gfx::ShapedTextFlags aFlags, |
1222 | | nsTextFrameUtils::Flags aFlags2); |
1223 | | |
1224 | | already_AddRefed<gfxTextRun> |
1225 | | MakeBlankTextRun(uint32_t aLength, const Parameters *aParams, |
1226 | | mozilla::gfx::ShapedTextFlags aFlags, |
1227 | | nsTextFrameUtils::Flags aFlags2); |
1228 | | |
1229 | | // Initialize the list of fonts |
1230 | | void BuildFontList(); |
1231 | | |
1232 | | // Get the font at index i within the fontlist. |
1233 | | // Will initiate userfont load if not already loaded. |
1234 | | // May return null if userfont not loaded or if font invalid |
1235 | | gfxFont* GetFontAt(int32_t i, uint32_t aCh = 0x20); |
1236 | | |
1237 | | // Whether there's a font loading for a given family in the fontlist |
1238 | | // for a given character |
1239 | | bool FontLoadingForFamily(gfxFontFamily* aFamily, uint32_t aCh) const; |
1240 | | |
1241 | | // will always return a font or force a shutdown |
1242 | | gfxFont* GetDefaultFont(); |
1243 | | |
1244 | | // Init this font group's font metrics. If there no bad fonts, you don't need to call this. |
1245 | | // But if there are one or more bad fonts which have bad underline offset, |
1246 | | // you should call this with the *first* bad font. |
1247 | | void InitMetricsForBadFont(gfxFont* aBadFont); |
1248 | | |
1249 | | // Set up the textrun glyphs for an entire text run: |
1250 | | // find script runs, and then call InitScriptRun for each |
1251 | | template<typename T> |
1252 | | void InitTextRun(DrawTarget* aDrawTarget, |
1253 | | gfxTextRun *aTextRun, |
1254 | | const T *aString, |
1255 | | uint32_t aLength, |
1256 | | gfxMissingFontRecorder *aMFR); |
1257 | | |
1258 | | // InitTextRun helper to handle a single script run, by finding font ranges |
1259 | | // and calling each font's InitTextRun() as appropriate |
1260 | | template<typename T> |
1261 | | void InitScriptRun(DrawTarget* aDrawTarget, |
1262 | | gfxTextRun *aTextRun, |
1263 | | const T *aString, |
1264 | | uint32_t aScriptRunStart, |
1265 | | uint32_t aScriptRunEnd, |
1266 | | Script aRunScript, |
1267 | | gfxMissingFontRecorder *aMFR); |
1268 | | |
1269 | | // Helper for font-matching: |
1270 | | // search all faces in a family for a fallback in cases where it's unclear |
1271 | | // whether the family might have a font for a given character |
1272 | | gfxFont* |
1273 | | FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh); |
1274 | | |
1275 | | // helper methods for looking up fonts |
1276 | | |
1277 | | // lookup and add a font with a given name (i.e. *not* a generic!) |
1278 | | void AddPlatformFont(const nsACString& aName, |
1279 | | nsTArray<FamilyAndGeneric>& aFamilyList); |
1280 | | |
1281 | | // do style selection and add entries to list |
1282 | | void AddFamilyToFontList(gfxFontFamily* aFamily, |
1283 | | mozilla::FontFamilyType aGeneric); |
1284 | | }; |
1285 | | |
1286 | | // A "missing font recorder" is to be used during text-run creation to keep |
1287 | | // a record of any scripts encountered for which font coverage was lacking; |
1288 | | // when Flush() is called, it sends a notification that front-end code can use |
1289 | | // to download fonts on demand (or whatever else it wants to do). |
1290 | | |
1291 | 0 | #define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify" |
1292 | | |
1293 | | class gfxMissingFontRecorder { |
1294 | | public: |
1295 | | gfxMissingFontRecorder() |
1296 | 0 | { |
1297 | 0 | MOZ_COUNT_CTOR(gfxMissingFontRecorder); |
1298 | 0 | memset(&mMissingFonts, 0, sizeof(mMissingFonts)); |
1299 | 0 | } |
1300 | | |
1301 | | ~gfxMissingFontRecorder() |
1302 | 0 | { |
1303 | | #ifdef DEBUG |
1304 | | for (uint32_t i = 0; i < kNumScriptBitsWords; i++) { |
1305 | | NS_ASSERTION(mMissingFonts[i] == 0, |
1306 | | "failed to flush the missing-font recorder"); |
1307 | | } |
1308 | | #endif |
1309 | | MOZ_COUNT_DTOR(gfxMissingFontRecorder); |
1310 | 0 | } |
1311 | | |
1312 | | // record this script code in our mMissingFonts bitset |
1313 | | void RecordScript(mozilla::unicode::Script aScriptCode) |
1314 | | { |
1315 | | mMissingFonts[static_cast<uint32_t>(aScriptCode) >> 5] |= |
1316 | | (1 << (static_cast<uint32_t>(aScriptCode) & 0x1f)); |
1317 | | } |
1318 | | |
1319 | | // send a notification of any missing-scripts that have been |
1320 | | // recorded, and clear the mMissingFonts set for re-use |
1321 | | void Flush(); |
1322 | | |
1323 | | // forget any missing-scripts that have been recorded up to now; |
1324 | | // called before discarding a recorder we no longer care about |
1325 | | void Clear() |
1326 | 0 | { |
1327 | 0 | memset(&mMissingFonts, 0, sizeof(mMissingFonts)); |
1328 | 0 | } |
1329 | | |
1330 | | private: |
1331 | | // Number of 32-bit words needed for the missing-script flags |
1332 | | static const uint32_t kNumScriptBitsWords = |
1333 | | ((static_cast<int>(mozilla::unicode::Script::NUM_SCRIPT_CODES) + 31) / 32); |
1334 | | uint32_t mMissingFonts[kNumScriptBitsWords]; |
1335 | | }; |
1336 | | |
1337 | | #endif |