1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Foundation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2005-2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Stuart Parmenter <stuart@mozilla.com>
23 : * Masayuki Nakano <masayuki@d-toybox.com>
24 : * John Daggett <jdaggett@mozilla.com>
25 : * Jonathan Kew <jfkthame@gmail.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef GFX_FONT_H
42 : #define GFX_FONT_H
43 :
44 : #include "prtypes.h"
45 : #include "nsAlgorithm.h"
46 : #include "gfxTypes.h"
47 : #include "nsString.h"
48 : #include "gfxPoint.h"
49 : #include "gfxFontUtils.h"
50 : #include "nsTArray.h"
51 : #include "nsTHashtable.h"
52 : #include "nsHashKeys.h"
53 : #include "gfxSkipChars.h"
54 : #include "gfxRect.h"
55 : #include "nsExpirationTracker.h"
56 : #include "gfxFontConstants.h"
57 : #include "gfxPlatform.h"
58 : #include "nsIAtom.h"
59 : #include "nsISupportsImpl.h"
60 : #include "gfxPattern.h"
61 : #include "mozilla/HashFunctions.h"
62 :
63 : typedef struct _cairo_scaled_font cairo_scaled_font_t;
64 :
65 : #ifdef DEBUG
66 : #include <stdio.h>
67 : #endif
68 :
69 : class gfxContext;
70 : class gfxTextRun;
71 : class gfxFont;
72 : class gfxFontFamily;
73 : class gfxFontGroup;
74 : class gfxUserFontSet;
75 : class gfxUserFontData;
76 : class gfxShapedWord;
77 :
78 : class nsILanguageAtomService;
79 :
80 : typedef struct _hb_blob_t hb_blob_t;
81 :
82 : // We should eliminate these synonyms when it won't cause many merge conflicts.
83 : #define FONT_STYLE_NORMAL NS_FONT_STYLE_NORMAL
84 : #define FONT_STYLE_ITALIC NS_FONT_STYLE_ITALIC
85 : #define FONT_STYLE_OBLIQUE NS_FONT_STYLE_OBLIQUE
86 :
87 : // We should eliminate these synonyms when it won't cause many merge conflicts.
88 : #define FONT_WEIGHT_NORMAL NS_FONT_WEIGHT_NORMAL
89 : #define FONT_WEIGHT_BOLD NS_FONT_WEIGHT_BOLD
90 :
91 : #define FONT_MAX_SIZE 2000.0
92 :
93 : #define NO_FONT_LANGUAGE_OVERRIDE 0
94 :
95 : // An OpenType feature tag and value pair
96 0 : struct THEBES_API gfxFontFeature {
97 : PRUint32 mTag; // see http://www.microsoft.com/typography/otspec/featuretags.htm
98 : PRUint32 mValue; // 0 = off, 1 = on, larger values may be used as parameters
99 : // to features that select among multiple alternatives
100 : };
101 :
102 : inline bool
103 0 : operator<(const gfxFontFeature& a, const gfxFontFeature& b)
104 : {
105 0 : return (a.mTag < b.mTag) || ((a.mTag == b.mTag) && (a.mValue < b.mValue));
106 : }
107 :
108 : inline bool
109 0 : operator==(const gfxFontFeature& a, const gfxFontFeature& b)
110 : {
111 0 : return (a.mTag == b.mTag) && (a.mValue == b.mValue);
112 : }
113 :
114 :
115 0 : struct THEBES_API gfxFontStyle {
116 : gfxFontStyle();
117 : gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, PRInt16 aStretch,
118 : gfxFloat aSize, nsIAtom *aLanguage,
119 : float aSizeAdjust, bool aSystemFont,
120 : bool aPrinterFont,
121 : const nsString& aFeatureSettings,
122 : const nsString& aLanguageOverride);
123 : gfxFontStyle(const gfxFontStyle& aStyle);
124 :
125 : // The style of font (normal, italic, oblique)
126 : PRUint8 style : 7;
127 :
128 : // Say that this font is a system font and therefore does not
129 : // require certain fixup that we do for fonts from untrusted
130 : // sources.
131 : bool systemFont : 1;
132 :
133 : // Say that this font is used for print or print preview.
134 : bool printerFont : 1;
135 :
136 : // The weight of the font: 100, 200, ... 900.
137 : PRUint16 weight;
138 :
139 : // The stretch of the font (the sum of various NS_FONT_STRETCH_*
140 : // constants; see gfxFontConstants.h).
141 : PRInt16 stretch;
142 :
143 : // The logical size of the font, in pixels
144 : gfxFloat size;
145 :
146 : // The aspect-value (ie., the ratio actualsize:actualxheight) that any
147 : // actual physical font created from this font structure must have when
148 : // rendering or measuring a string. A value of 0 means no adjustment
149 : // needs to be done.
150 : float sizeAdjust;
151 :
152 : // the language (may be an internal langGroup code rather than an actual
153 : // language code) specified in the document or element's lang property,
154 : // or inferred from the charset
155 : nsRefPtr<nsIAtom> language;
156 :
157 : // Language system tag, to override document language;
158 : // an OpenType "language system" tag represented as a 32-bit integer
159 : // (see http://www.microsoft.com/typography/otspec/languagetags.htm).
160 : // Normally 0, so font rendering will use the document or element language
161 : // (see above) to control any language-specific rendering, but the author
162 : // can override this for cases where the options implemented in the font
163 : // do not directly match the actual language. (E.g. lang may be Macedonian,
164 : // but the font in use does not explicitly support this; the author can
165 : // use font-language-override to request the Serbian option in the font
166 : // in order to get correct glyph shapes.)
167 : PRUint32 languageOverride;
168 :
169 : // custom opentype feature settings
170 : nsTArray<gfxFontFeature> featureSettings;
171 :
172 : // Return the final adjusted font size for the given aspect ratio.
173 : // Not meant to be called when sizeAdjust = 0.
174 : gfxFloat GetAdjustedSize(gfxFloat aspect) const {
175 : NS_ASSERTION(sizeAdjust != 0.0, "Not meant to be called when sizeAdjust = 0");
176 : gfxFloat adjustedSize = NS_MAX(NS_round(size*(sizeAdjust/aspect)), 1.0);
177 : return NS_MIN(adjustedSize, FONT_MAX_SIZE);
178 : }
179 :
180 0 : PLDHashNumber Hash() const {
181 : return ((style + (systemFont << 7) +
182 : (weight << 8)) + PRUint32(size*1000) + PRUint32(sizeAdjust*1000)) ^
183 0 : nsISupportsHashKey::HashKey(language);
184 : }
185 :
186 : PRInt8 ComputeWeight() const;
187 :
188 0 : bool Equals(const gfxFontStyle& other) const {
189 : return (size == other.size) &&
190 : (style == other.style) &&
191 : (systemFont == other.systemFont) &&
192 : (printerFont == other.printerFont) &&
193 : (weight == other.weight) &&
194 : (stretch == other.stretch) &&
195 0 : (language == other.language) &&
196 : (sizeAdjust == other.sizeAdjust) &&
197 0 : (featureSettings == other.featureSettings) &&
198 0 : (languageOverride == other.languageOverride);
199 : }
200 :
201 : static void ParseFontFeatureSettings(const nsString& aFeatureString,
202 : nsTArray<gfxFontFeature>& aFeatures);
203 :
204 : static PRUint32 ParseFontLanguageOverride(const nsString& aLangTag);
205 : };
206 :
207 : class gfxFontEntry {
208 : public:
209 0 : NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
210 :
211 0 : gfxFontEntry(const nsAString& aName, gfxFontFamily *aFamily = nsnull,
212 : bool aIsStandardFace = false) :
213 : mName(aName), mItalic(false), mFixedPitch(false),
214 : mIsProxy(false), mIsValid(true),
215 : mIsBadUnderlineFont(false), mIsUserFont(false),
216 : mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
217 : mSymbolFont(false),
218 : mIgnoreGDEF(false),
219 : mIgnoreGSUB(false),
220 : mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
221 : #ifdef MOZ_GRAPHITE
222 : mCheckedForGraphiteTables(false),
223 : #endif
224 : mHasCmapTable(false),
225 : mCmapInitialized(false),
226 : mUVSOffset(0), mUVSData(nsnull),
227 : mUserFontData(nsnull),
228 : mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
229 0 : mFamily(aFamily)
230 0 : { }
231 :
232 : virtual ~gfxFontEntry();
233 :
234 : // unique name for the face, *not* the family; not necessarily the
235 : // "real" or user-friendly name, may be an internal identifier
236 0 : const nsString& Name() const { return mName; }
237 :
238 : // the "real" name of the face, if available from the font resource
239 : // (may be expensive); returns Name() if nothing better is available
240 : virtual nsString RealFaceName();
241 :
242 0 : gfxFontFamily* Family() const { return mFamily; }
243 :
244 0 : PRUint16 Weight() const { return mWeight; }
245 0 : PRInt16 Stretch() const { return mStretch; }
246 :
247 0 : bool IsUserFont() const { return mIsUserFont; }
248 : bool IsLocalUserFont() const { return mIsLocalUserFont; }
249 0 : bool IsFixedPitch() const { return mFixedPitch; }
250 0 : bool IsItalic() const { return mItalic; }
251 0 : bool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above
252 0 : bool IgnoreGDEF() const { return mIgnoreGDEF; }
253 0 : bool IgnoreGSUB() const { return mIgnoreGSUB; }
254 :
255 : virtual bool IsSymbolFont();
256 :
257 : #ifdef MOZ_GRAPHITE
258 0 : inline bool HasGraphiteTables() {
259 0 : if (!mCheckedForGraphiteTables) {
260 0 : CheckForGraphiteTables();
261 0 : mCheckedForGraphiteTables = true;
262 : }
263 0 : return mHasGraphiteTables;
264 : }
265 : #endif
266 :
267 0 : inline bool HasCmapTable() {
268 0 : if (!mCmapInitialized) {
269 0 : ReadCMAP();
270 : }
271 0 : return mHasCmapTable;
272 : }
273 :
274 0 : inline bool HasCharacter(PRUint32 ch) {
275 0 : if (mCharacterMap.test(ch))
276 0 : return true;
277 :
278 0 : return TestCharacterMap(ch);
279 : }
280 :
281 0 : virtual bool SkipDuringSystemFallback() { return false; }
282 : virtual bool TestCharacterMap(PRUint32 aCh);
283 : nsresult InitializeUVSMap();
284 : PRUint16 GetUVSGlyph(PRUint32 aCh, PRUint32 aVS);
285 : virtual nsresult ReadCMAP();
286 :
287 0 : virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
288 0 : return true;
289 : }
290 0 : virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
291 0 : return true;
292 : }
293 :
294 0 : virtual nsresult GetFontTable(PRUint32 aTableTag, FallibleTArray<PRUint8>& aBuffer) {
295 0 : return NS_ERROR_FAILURE; // all platform subclasses should reimplement this!
296 : }
297 :
298 0 : void SetFamily(gfxFontFamily* aFamily) {
299 0 : mFamily = aFamily;
300 0 : }
301 :
302 : virtual nsString FamilyName() const;
303 :
304 : already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
305 : bool aNeedsBold);
306 :
307 : // Get an existing font table cache entry in aBlob if it has been
308 : // registered, or return false if not. Callers must call
309 : // hb_blob_destroy on aBlob if true is returned.
310 : //
311 : // Note that some gfxFont implementations may not call this at all,
312 : // if it is more efficient to get the table from the OS at that level.
313 : bool GetExistingFontTable(PRUint32 aTag, hb_blob_t** aBlob);
314 :
315 : // Elements of aTable are transferred (not copied) to and returned in a
316 : // new hb_blob_t which is registered on the gfxFontEntry, but the initial
317 : // reference is owned by the caller. Removing the last reference
318 : // unregisters the table from the font entry.
319 : //
320 : // Pass NULL for aBuffer to indicate that the table is not present and
321 : // NULL will be returned. Also returns NULL on OOM.
322 : hb_blob_t *ShareFontTableAndGetBlob(PRUint32 aTag,
323 : FallibleTArray<PRUint8>* aTable);
324 :
325 : nsString mName;
326 :
327 : bool mItalic : 1;
328 : bool mFixedPitch : 1;
329 : bool mIsProxy : 1;
330 : bool mIsValid : 1;
331 : bool mIsBadUnderlineFont : 1;
332 : bool mIsUserFont : 1;
333 : bool mIsLocalUserFont : 1;
334 : bool mStandardFace : 1;
335 : bool mSymbolFont : 1;
336 : bool mIgnoreGDEF : 1;
337 : bool mIgnoreGSUB : 1;
338 :
339 : PRUint16 mWeight;
340 : PRInt16 mStretch;
341 :
342 : #ifdef MOZ_GRAPHITE
343 : bool mHasGraphiteTables;
344 : bool mCheckedForGraphiteTables;
345 : #endif
346 : bool mHasCmapTable;
347 : bool mCmapInitialized;
348 : gfxSparseBitSet mCharacterMap;
349 : PRUint32 mUVSOffset;
350 : nsAutoArrayPtr<PRUint8> mUVSData;
351 : gfxUserFontData* mUserFontData;
352 :
353 : nsTArray<gfxFontFeature> mFeatureSettings;
354 : PRUint32 mLanguageOverride;
355 :
356 : protected:
357 : friend class gfxPlatformFontList;
358 : friend class gfxMacPlatformFontList;
359 : friend class gfxUserFcFontEntry;
360 : friend class gfxFontFamily;
361 : friend class gfxSingleFaceMacFontFamily;
362 :
363 : gfxFontEntry() :
364 : mItalic(false), mFixedPitch(false),
365 : mIsProxy(false), mIsValid(true),
366 : mIsBadUnderlineFont(false),
367 : mIsUserFont(false),
368 : mIsLocalUserFont(false),
369 : mStandardFace(false),
370 : mSymbolFont(false),
371 : mIgnoreGDEF(false),
372 : mIgnoreGSUB(false),
373 : mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
374 : #ifdef MOZ_GRAPHITE
375 : mCheckedForGraphiteTables(false),
376 : #endif
377 : mHasCmapTable(false),
378 : mCmapInitialized(false),
379 : mUVSOffset(0), mUVSData(nsnull),
380 : mUserFontData(nsnull),
381 : mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
382 : mFamily(nsnull)
383 : { }
384 :
385 0 : virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) {
386 0 : NS_NOTREACHED("oops, somebody didn't override CreateFontInstance");
387 0 : return nsnull;
388 : }
389 :
390 : #ifdef MOZ_GRAPHITE
391 : virtual void CheckForGraphiteTables();
392 : #endif
393 :
394 : gfxFontFamily *mFamily;
395 :
396 : private:
397 :
398 : /**
399 : * Font table hashtable, to support GetFontTable for harfbuzz.
400 : *
401 : * The harfbuzz shaper (and potentially other clients) needs access to raw
402 : * font table data. This needs to be cached so that it can be used
403 : * repeatedly (each time we construct a text run; in some cases, for
404 : * each character/glyph within the run) without re-fetching large tables
405 : * every time.
406 : *
407 : * Because we may instantiate many gfxFonts for the same physical font
408 : * file (at different sizes), we should ensure that they can share a
409 : * single cached copy of the font tables. To do this, we implement table
410 : * access and sharing on the fontEntry rather than the font itself.
411 : *
412 : * The default implementation uses GetFontTable() to read font table
413 : * data into byte arrays, and wraps them in blobs which are registered in
414 : * a hashtable. The hashtable can then return pre-existing blobs to
415 : * harfbuzz.
416 : *
417 : * Harfbuzz will "destroy" the blobs when it is finished with them. When
418 : * the last blob reference is removed, the FontTableBlobData user data
419 : * will remove the blob from the hashtable if still registered.
420 : */
421 :
422 : class FontTableBlobData;
423 :
424 : /**
425 : * FontTableHashEntry manages the entries of hb_blob_ts for two
426 : * different situations:
427 : *
428 : * The common situation is to share font table across fonts with the same
429 : * font entry (but different sizes) for use by HarfBuzz. The hashtable
430 : * does not own a strong reference to the blob, but keeps a weak pointer,
431 : * managed by FontTableBlobData. Similarly FontTableBlobData keeps only a
432 : * weak pointer to the hashtable, managed by FontTableHashEntry.
433 : *
434 : * Some font tables are saved here before they would get stripped by OTS
435 : * sanitizing. These are retained for harfbuzz, which does its own
436 : * sanitizing. The hashtable owns a reference, so ownership is simple.
437 : */
438 :
439 : class FontTableHashEntry : public nsUint32HashKey
440 : {
441 : public:
442 : // Declarations for nsTHashtable
443 :
444 : typedef nsUint32HashKey KeyClass;
445 : typedef KeyClass::KeyType KeyType;
446 : typedef KeyClass::KeyTypePointer KeyTypePointer;
447 :
448 0 : FontTableHashEntry(KeyTypePointer aTag)
449 0 : : KeyClass(aTag), mBlob() { };
450 : // Copying transfers blob association.
451 : FontTableHashEntry(FontTableHashEntry& toCopy)
452 : : KeyClass(toCopy), mBlob(toCopy.mBlob)
453 : {
454 : toCopy.mBlob = nsnull;
455 : }
456 :
457 0 : ~FontTableHashEntry() { Clear(); }
458 :
459 : // FontTable/Blob API
460 :
461 : // Transfer (not copy) elements of aTable to a new hb_blob_t and
462 : // return ownership to the caller. A weak reference to the blob is
463 : // recorded in the hashtable entry so that others may use the same
464 : // table.
465 : hb_blob_t *
466 : ShareTableAndGetBlob(FallibleTArray<PRUint8>& aTable,
467 : nsTHashtable<FontTableHashEntry> *aHashtable);
468 :
469 : // Transfer (not copy) elements of aTable to a new hb_blob_t that is
470 : // owned by the hashtable entry.
471 : void SaveTable(FallibleTArray<PRUint8>& aTable);
472 :
473 : // Return a strong reference to the blob.
474 : // Callers must hb_blob_destroy the returned blob.
475 : hb_blob_t *GetBlob() const;
476 :
477 : void Clear();
478 :
479 : private:
480 : static void DeleteFontTableBlobData(void *aBlobData);
481 : // not implemented
482 : FontTableHashEntry& operator=(FontTableHashEntry& toCopy);
483 :
484 : FontTableBlobData *mSharedBlobData;
485 : hb_blob_t *mBlob;
486 : };
487 :
488 : nsTHashtable<FontTableHashEntry> mFontTableCache;
489 :
490 : gfxFontEntry(const gfxFontEntry&);
491 : gfxFontEntry& operator=(const gfxFontEntry&);
492 : };
493 :
494 :
495 : // used when iterating over all fonts looking for a match for a given character
496 0 : struct GlobalFontMatch {
497 0 : GlobalFontMatch(const PRUint32 aCharacter,
498 : PRInt32 aRunScript,
499 : const gfxFontStyle *aStyle) :
500 : mCh(aCharacter), mRunScript(aRunScript), mStyle(aStyle),
501 0 : mMatchRank(0), mCount(0), mCmapsTested(0)
502 : {
503 :
504 0 : }
505 :
506 : const PRUint32 mCh; // codepoint to be matched
507 : PRInt32 mRunScript; // Unicode script for the codepoint
508 : const gfxFontStyle* mStyle; // style to match
509 : PRInt32 mMatchRank; // metric indicating closest match
510 : nsRefPtr<gfxFontEntry> mBestMatch; // current best match
511 : PRUint32 mCount; // number of fonts matched
512 : PRUint32 mCmapsTested; // number of cmaps tested
513 : };
514 :
515 : class gfxFontFamily {
516 : public:
517 0 : NS_INLINE_DECL_REFCOUNTING(gfxFontFamily)
518 :
519 0 : gfxFontFamily(const nsAString& aName) :
520 : mName(aName),
521 : mOtherFamilyNamesInitialized(false),
522 : mHasOtherFamilyNames(false),
523 : mFaceNamesInitialized(false),
524 : mHasStyles(false),
525 : mIsSimpleFamily(false),
526 : mIsBadUnderlineFamily(false),
527 0 : mCharacterMapInitialized(false)
528 0 : { }
529 :
530 0 : virtual ~gfxFontFamily() {
531 : // clear Family pointers in our faces; the font entries might stay
532 : // alive due to cached font objects, but they can no longer refer
533 : // to their families.
534 0 : PRUint32 i = mAvailableFonts.Length();
535 0 : while (i) {
536 0 : gfxFontEntry *fe = mAvailableFonts[--i];
537 0 : if (fe) {
538 0 : fe->SetFamily(nsnull);
539 : }
540 : }
541 0 : }
542 :
543 0 : const nsString& Name() { return mName; }
544 :
545 : virtual void LocalizedName(nsAString& aLocalizedName);
546 : virtual bool HasOtherFamilyNames();
547 :
548 0 : nsTArray<nsRefPtr<gfxFontEntry> >& GetFontList() { return mAvailableFonts; }
549 :
550 : void AddFontEntry(nsRefPtr<gfxFontEntry> aFontEntry) {
551 : // bug 589682 - set the IgnoreGDEF flag on entries for Italic faces
552 : // of Times New Roman, because of buggy table in those fonts
553 : if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() &&
554 : Name().EqualsLiteral("Times New Roman"))
555 : {
556 : aFontEntry->mIgnoreGDEF = true;
557 : }
558 : mAvailableFonts.AppendElement(aFontEntry);
559 : aFontEntry->SetFamily(this);
560 : }
561 :
562 : // note that the styles for this family have been added
563 : void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; }
564 :
565 : // choose a specific face to match a style using CSS font matching
566 : // rules (weight matching occurs here). may return a face that doesn't
567 : // precisely match (e.g. normal face when no italic face exists).
568 : // aNeedsSyntheticBold is set to true when synthetic bolding is
569 : // needed, false otherwise
570 : gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle,
571 : bool& aNeedsSyntheticBold);
572 :
573 : // checks for a matching font within the family
574 : // used as part of the font fallback process
575 : void FindFontForChar(GlobalFontMatch *aMatchData);
576 :
577 : // checks all fonts for a matching font within the family
578 : void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
579 :
580 : // read in other family names, if any, and use functor to add each into cache
581 : virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
582 :
583 : // set when other family names have been read in
584 : void SetOtherFamilyNamesInitialized() {
585 : mOtherFamilyNamesInitialized = true;
586 : }
587 :
588 : // read in other localized family names, fullnames and Postscript names
589 : // for all faces and append to lookup tables
590 : virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
591 : bool aNeedFullnamePostscriptNames);
592 :
593 : // find faces belonging to this family (platform implementations override this;
594 : // should be made pure virtual once all subclasses have been updated)
595 0 : virtual void FindStyleVariations() { }
596 :
597 : // search for a specific face using the Postscript name
598 : gfxFontEntry* FindFont(const nsAString& aPostscriptName);
599 :
600 : // read in cmaps for all the faces
601 0 : void ReadAllCMAPs() {
602 0 : PRUint32 i, numFonts = mAvailableFonts.Length();
603 0 : for (i = 0; i < numFonts; i++) {
604 0 : gfxFontEntry *fe = mAvailableFonts[i];
605 0 : if (!fe) {
606 0 : continue;
607 : }
608 0 : fe->ReadCMAP();
609 0 : mCharacterMap.Union(fe->mCharacterMap);
610 : }
611 0 : mCharacterMap.Compact();
612 0 : mCharacterMapInitialized = true;
613 0 : }
614 :
615 0 : bool TestCharacterMap(PRUint32 aCh) {
616 0 : if (!mCharacterMapInitialized) {
617 0 : ReadAllCMAPs();
618 : }
619 0 : return mCharacterMap.test(aCh);
620 : }
621 :
622 0 : void ResetCharacterMap() {
623 0 : mCharacterMap.reset();
624 0 : mCharacterMapInitialized = false;
625 0 : }
626 :
627 : // mark this family as being in the "bad" underline offset blacklist
628 0 : void SetBadUnderlineFamily() {
629 0 : mIsBadUnderlineFamily = true;
630 0 : if (mHasStyles) {
631 0 : SetBadUnderlineFonts();
632 : }
633 0 : }
634 :
635 : bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; }
636 :
637 : // sort available fonts to put preferred (standard) faces towards the end
638 : void SortAvailableFonts();
639 :
640 : // check whether the family fits into the simple 4-face model,
641 : // so we can use simplified style-matching;
642 : // if so set the mIsSimpleFamily flag (defaults to False before we've checked)
643 : void CheckForSimpleFamily();
644 :
645 : protected:
646 : // fills in an array with weights of faces that match style,
647 : // returns whether any matching entries found
648 : virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
649 : bool anItalic, PRInt16 aStretch);
650 :
651 : bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
652 : FallibleTArray<PRUint8>& aNameTable,
653 : bool useFullName = false);
654 :
655 : // set whether this font family is in "bad" underline offset blacklist.
656 0 : void SetBadUnderlineFonts() {
657 0 : PRUint32 i, numFonts = mAvailableFonts.Length();
658 0 : for (i = 0; i < numFonts; i++) {
659 0 : if (mAvailableFonts[i]) {
660 0 : mAvailableFonts[i]->mIsBadUnderlineFont = true;
661 : }
662 : }
663 0 : }
664 :
665 : nsString mName;
666 : nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
667 : gfxSparseBitSet mCharacterMap;
668 : bool mOtherFamilyNamesInitialized;
669 : bool mHasOtherFamilyNames;
670 : bool mFaceNamesInitialized;
671 : bool mHasStyles;
672 : bool mIsSimpleFamily;
673 : bool mIsBadUnderlineFamily;
674 : bool mCharacterMapInitialized;
675 :
676 : enum {
677 : // for "simple" families, the faces are stored in mAvailableFonts
678 : // with fixed positions:
679 : kRegularFaceIndex = 0,
680 : kBoldFaceIndex = 1,
681 : kItalicFaceIndex = 2,
682 : kBoldItalicFaceIndex = 3,
683 : // mask values for selecting face with bold and/or italic attributes
684 : kBoldMask = 0x01,
685 : kItalicMask = 0x02
686 : };
687 : };
688 :
689 0 : struct gfxTextRange {
690 : enum {
691 : // flags for recording the kind of font-matching that was used
692 : kFontGroup = 0x0001,
693 : kPrefsFallback = 0x0002,
694 : kSystemFallback = 0x0004
695 : };
696 0 : gfxTextRange(PRUint32 aStart, PRUint32 aEnd,
697 : gfxFont* aFont, PRUint8 aMatchType)
698 : : start(aStart),
699 : end(aEnd),
700 : font(aFont),
701 0 : matchType(aMatchType)
702 0 : { }
703 0 : PRUint32 Length() const { return end - start; }
704 : PRUint32 start, end;
705 : nsRefPtr<gfxFont> font;
706 : PRUint8 matchType;
707 : };
708 :
709 :
710 : /**
711 : * Font cache design:
712 : *
713 : * The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style).
714 : * It does not add a reference to the fonts it contains.
715 : * When a font's refcount decreases to zero, instead of deleting it we
716 : * add it to our expiration tracker.
717 : * The expiration tracker tracks fonts with zero refcount. After a certain
718 : * period of time, such fonts expire and are deleted.
719 : *
720 : * We're using 3 generations with a ten-second generation interval, so
721 : * zero-refcount fonts will be deleted 20-30 seconds after their refcount
722 : * goes to zero, if timer events fire in a timely manner.
723 : *
724 : * The font cache also handles timed expiration of cached ShapedWords
725 : * for "persistent" fonts: it has a repeating timer, and notifies
726 : * each cached font to "age" its shaped words. The words will be released
727 : * by the fonts if they get aged three times without being re-used in the
728 : * meantime.
729 : *
730 : * Note that the ShapedWord timeout is much larger than the font timeout,
731 : * so that in the case of a short-lived font, we'll discard the gfxFont
732 : * completely, with all its words, and avoid the cost of aging the words
733 : * individually. That only happens with longer-lived fonts.
734 : */
735 : class THEBES_API gfxFontCache MOZ_FINAL : public nsExpirationTracker<gfxFont,3> {
736 : public:
737 : enum {
738 : FONT_TIMEOUT_SECONDS = 10,
739 : SHAPED_WORD_TIMEOUT_SECONDS = 60
740 : };
741 :
742 : gfxFontCache();
743 : ~gfxFontCache();
744 :
745 : /*
746 : * Get the global gfxFontCache. You must call Init() before
747 : * calling this method --- the result will not be null.
748 : */
749 0 : static gfxFontCache* GetCache() {
750 0 : return gGlobalCache;
751 : }
752 :
753 : static nsresult Init();
754 : // It's OK to call this even if Init() has not been called.
755 : static void Shutdown();
756 :
757 : // Look up a font in the cache. Returns an addrefed pointer, or null
758 : // if there's nothing matching in the cache
759 : already_AddRefed<gfxFont> Lookup(const gfxFontEntry *aFontEntry,
760 : const gfxFontStyle *aStyle);
761 : // We created a new font (presumably because Lookup returned null);
762 : // put it in the cache. The font's refcount should be nonzero. It is
763 : // allowable to add a new font even if there is one already in the
764 : // cache with the same key; we'll forget about the old one.
765 : void AddNew(gfxFont *aFont);
766 :
767 : // The font's refcount has gone to zero; give ownership of it to
768 : // the cache. We delete it if it's not acquired again after a certain
769 : // amount of time.
770 : void NotifyReleased(gfxFont *aFont);
771 :
772 : // This gets called when the timeout has expired on a zero-refcount
773 : // font; we just delete it.
774 : virtual void NotifyExpired(gfxFont *aFont);
775 :
776 : // Cleans out the hashtable and removes expired fonts waiting for cleanup.
777 : // Other gfxFont objects may be still in use but they will be pushed
778 : // into the expiration queues and removed.
779 : void Flush() {
780 : mFonts.Clear();
781 : AgeAllGenerations();
782 : }
783 :
784 0 : void FlushShapedWordCaches() {
785 0 : mFonts.EnumerateEntries(ClearCachedWordsForFont, nsnull);
786 0 : }
787 :
788 : protected:
789 : void DestroyFont(gfxFont *aFont);
790 :
791 : static gfxFontCache *gGlobalCache;
792 :
793 : struct Key {
794 : const gfxFontEntry* mFontEntry;
795 : const gfxFontStyle* mStyle;
796 0 : Key(const gfxFontEntry* aFontEntry, const gfxFontStyle* aStyle)
797 0 : : mFontEntry(aFontEntry), mStyle(aStyle) {}
798 : };
799 :
800 : class HashEntry : public PLDHashEntryHdr {
801 : public:
802 : typedef const Key& KeyType;
803 : typedef const Key* KeyTypePointer;
804 :
805 : // When constructing a new entry in the hashtable, we'll leave this
806 : // blank. The caller of Put() will fill this in.
807 0 : HashEntry(KeyTypePointer aStr) : mFont(nsnull) { }
808 : HashEntry(const HashEntry& toCopy) : mFont(toCopy.mFont) { }
809 0 : ~HashEntry() { }
810 :
811 : bool KeyEquals(const KeyTypePointer aKey) const;
812 0 : static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
813 0 : static PLDHashNumber HashKey(const KeyTypePointer aKey) {
814 0 : return mozilla::HashGeneric(aKey->mStyle->Hash(), aKey->mFontEntry);
815 : }
816 : enum { ALLOW_MEMMOVE = true };
817 :
818 : gfxFont* mFont;
819 : };
820 :
821 : nsTHashtable<HashEntry> mFonts;
822 :
823 : static PLDHashOperator ClearCachedWordsForFont(HashEntry* aHashEntry, void*);
824 : static PLDHashOperator AgeCachedWordsForFont(HashEntry* aHashEntry, void*);
825 : static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache);
826 : nsCOMPtr<nsITimer> mWordCacheExpirationTimer;
827 : };
828 :
829 0 : class THEBES_API gfxTextRunFactory {
830 0 : NS_INLINE_DECL_REFCOUNTING(gfxTextRunFactory)
831 :
832 : public:
833 : // Flags in the mask 0xFFFF0000 are reserved for textrun clients
834 : // Flags in the mask 0x0000F000 are reserved for per-platform fonts
835 : // Flags in the mask 0x00000FFF are set by the textrun creator.
836 : enum {
837 : CACHE_TEXT_FLAGS = 0xF0000000,
838 : USER_TEXT_FLAGS = 0x0FFF0000,
839 : PLATFORM_TEXT_FLAGS = 0x0000F000,
840 : TEXTRUN_TEXT_FLAGS = 0x00000FFF,
841 : SETTABLE_FLAGS = CACHE_TEXT_FLAGS | USER_TEXT_FLAGS,
842 :
843 : /**
844 : * When set, the text string pointer used to create the text run
845 : * is guaranteed to be available during the lifetime of the text run.
846 : */
847 : TEXT_IS_PERSISTENT = 0x0001,
848 : /**
849 : * When set, the text is known to be all-ASCII (< 128).
850 : */
851 : TEXT_IS_ASCII = 0x0002,
852 : /**
853 : * When set, the text is RTL.
854 : */
855 : TEXT_IS_RTL = 0x0004,
856 : /**
857 : * When set, spacing is enabled and the textrun needs to call GetSpacing
858 : * on the spacing provider.
859 : */
860 : TEXT_ENABLE_SPACING = 0x0008,
861 : /**
862 : * When set, GetHyphenationBreaks may return true for some character
863 : * positions, otherwise it will always return false for all characters.
864 : */
865 : TEXT_ENABLE_HYPHEN_BREAKS = 0x0010,
866 : /**
867 : * When set, the text has no characters above 255 and it is stored
868 : * in the textrun in 8-bit format.
869 : */
870 : TEXT_IS_8BIT = 0x0020,
871 : /**
872 : * When set, the RunMetrics::mBoundingBox field will be initialized
873 : * properly based on glyph extents, in particular, glyph extents that
874 : * overflow the standard font-box (the box defined by the ascent, descent
875 : * and advance width of the glyph). When not set, it may just be the
876 : * standard font-box even if glyphs overflow.
877 : */
878 : TEXT_NEED_BOUNDING_BOX = 0x0040,
879 : /**
880 : * When set, optional ligatures are disabled. Ligatures that are
881 : * required for legible text should still be enabled.
882 : */
883 : TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0080,
884 : /**
885 : * When set, the textrun should favour speed of construction over
886 : * quality. This may involve disabling ligatures and/or kerning or
887 : * other effects.
888 : */
889 : TEXT_OPTIMIZE_SPEED = 0x0100,
890 : /**
891 : * For internal use by the memory reporter when accounting for
892 : * storage used by textruns.
893 : * Because the reporter may visit each textrun multiple times while
894 : * walking the frame trees and textrun cache, it needs to mark
895 : * textruns that have been seen so as to avoid multiple-accounting.
896 : */
897 : TEXT_RUN_SIZE_ACCOUNTED = 0x0200,
898 :
899 : /**
900 : * nsTextFrameThebes sets these, but they're defined here rather than
901 : * in nsTextFrameUtils.h because ShapedWord creation/caching also needs
902 : * to check the _INCOMING flag
903 : */
904 : TEXT_TRAILING_ARABICCHAR = 0x20000000,
905 : /**
906 : * When set, the previous character for this textrun was an Arabic
907 : * character. This is used for the context detection necessary for
908 : * bidi.numeral implementation.
909 : */
910 : TEXT_INCOMING_ARABICCHAR = 0x40000000,
911 :
912 : TEXT_UNUSED_FLAGS = 0x90000000
913 : };
914 :
915 : /**
916 : * This record contains all the parameters needed to initialize a textrun.
917 : */
918 : struct Parameters {
919 : // A reference context suggesting where the textrun will be rendered
920 : gfxContext *mContext;
921 : // Pointer to arbitrary user data (which should outlive the textrun)
922 : void *mUserData;
923 : // A description of which characters have been stripped from the original
924 : // DOM string to produce the characters in the textrun. May be null
925 : // if that information is not relevant.
926 : gfxSkipChars *mSkipChars;
927 : // A list of where linebreaks are currently placed in the textrun. May
928 : // be null if mInitialBreakCount is zero.
929 : PRUint32 *mInitialBreaks;
930 : PRUint32 mInitialBreakCount;
931 : // The ratio to use to convert device pixels to application layout units
932 : PRUint32 mAppUnitsPerDevUnit;
933 : };
934 :
935 0 : virtual ~gfxTextRunFactory() {}
936 : };
937 :
938 : /**
939 : * This stores glyph bounds information for a particular gfxFont, at
940 : * a particular appunits-per-dev-pixel ratio (because the compressed glyph
941 : * width array is stored in appunits).
942 : *
943 : * We store a hashtable from glyph IDs to float bounding rects. For the
944 : * common case where the glyph has no horizontal left bearing, and no
945 : * y overflow above the font ascent or below the font descent, and tight
946 : * bounding boxes are not required, we avoid storing the glyph ID in the hashtable
947 : * and instead consult an array of 16-bit glyph XMost values (in appunits).
948 : * This array always has an entry for the font's space glyph --- the width is
949 : * assumed to be zero.
950 : */
951 : class THEBES_API gfxGlyphExtents {
952 : public:
953 0 : gfxGlyphExtents(PRUint32 aAppUnitsPerDevUnit) :
954 0 : mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {
955 0 : MOZ_COUNT_CTOR(gfxGlyphExtents);
956 0 : mTightGlyphExtents.Init();
957 0 : }
958 : ~gfxGlyphExtents();
959 :
960 : enum { INVALID_WIDTH = 0xFFFF };
961 :
962 : // returns INVALID_WIDTH => not a contained glyph
963 : // Otherwise the glyph has no before-bearing or vertical bearings,
964 : // and the result is its width measured from the baseline origin, in
965 : // appunits.
966 0 : PRUint16 GetContainedGlyphWidthAppUnits(PRUint32 aGlyphID) const {
967 0 : return mContainedGlyphWidths.Get(aGlyphID);
968 : }
969 :
970 0 : bool IsGlyphKnown(PRUint32 aGlyphID) const {
971 0 : return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
972 0 : mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
973 : }
974 :
975 0 : bool IsGlyphKnownWithTightExtents(PRUint32 aGlyphID) const {
976 0 : return mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
977 : }
978 :
979 : // Get glyph extents; a rectangle relative to the left baseline origin
980 : // Returns true on success. Can fail on OOM or when aContext is null
981 : // and extents were not (successfully) prefetched.
982 : bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext,
983 : PRUint32 aGlyphID, gfxRect *aExtents);
984 :
985 0 : void SetContainedGlyphWidthAppUnits(PRUint32 aGlyphID, PRUint16 aWidth) {
986 0 : mContainedGlyphWidths.Set(aGlyphID, aWidth);
987 0 : }
988 : void SetTightGlyphExtents(PRUint32 aGlyphID, const gfxRect& aExtentsAppUnits);
989 :
990 0 : PRUint32 GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
991 :
992 : private:
993 0 : class HashEntry : public nsUint32HashKey {
994 : public:
995 : // When constructing a new entry in the hashtable, we'll leave this
996 : // blank. The caller of Put() will fill this in.
997 0 : HashEntry(KeyTypePointer aPtr) : nsUint32HashKey(aPtr) {}
998 : HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) {
999 : x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.height;
1000 : }
1001 :
1002 : float x, y, width, height;
1003 : };
1004 :
1005 : typedef PRUptrdiff PtrBits;
1006 : enum { BLOCK_SIZE_BITS = 7, BLOCK_SIZE = 1 << BLOCK_SIZE_BITS }; // 128-glyph blocks
1007 :
1008 0 : class GlyphWidths {
1009 : public:
1010 : void Set(PRUint32 aIndex, PRUint16 aValue);
1011 0 : PRUint16 Get(PRUint32 aIndex) const {
1012 0 : PRUint32 block = aIndex >> BLOCK_SIZE_BITS;
1013 0 : if (block >= mBlocks.Length())
1014 0 : return INVALID_WIDTH;
1015 0 : PtrBits bits = mBlocks[block];
1016 0 : if (!bits)
1017 0 : return INVALID_WIDTH;
1018 0 : PRUint32 indexInBlock = aIndex & (BLOCK_SIZE - 1);
1019 0 : if (bits & 0x1) {
1020 0 : if (GetGlyphOffset(bits) != indexInBlock)
1021 0 : return INVALID_WIDTH;
1022 0 : return GetWidth(bits);
1023 : }
1024 0 : PRUint16 *widths = reinterpret_cast<PRUint16 *>(bits);
1025 0 : return widths[indexInBlock];
1026 : }
1027 :
1028 : #ifdef DEBUG
1029 : PRUint32 ComputeSize();
1030 : #endif
1031 :
1032 : ~GlyphWidths();
1033 :
1034 : private:
1035 0 : static PRUint32 GetGlyphOffset(PtrBits aBits) {
1036 0 : NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
1037 0 : return (aBits >> 1) & ((1 << BLOCK_SIZE_BITS) - 1);
1038 : }
1039 0 : static PRUint32 GetWidth(PtrBits aBits) {
1040 0 : NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
1041 0 : return aBits >> (1 + BLOCK_SIZE_BITS);
1042 : }
1043 0 : static PtrBits MakeSingle(PRUint32 aGlyphOffset, PRUint16 aWidth) {
1044 0 : return (aWidth << (1 + BLOCK_SIZE_BITS)) + (aGlyphOffset << 1) + 1;
1045 : }
1046 :
1047 : nsTArray<PtrBits> mBlocks;
1048 : };
1049 :
1050 : GlyphWidths mContainedGlyphWidths;
1051 : nsTHashtable<HashEntry> mTightGlyphExtents;
1052 : PRUint32 mAppUnitsPerDevUnit;
1053 : };
1054 :
1055 : /**
1056 : * gfxFontShaper
1057 : *
1058 : * This class implements text shaping (character to glyph mapping and
1059 : * glyph layout). There is a gfxFontShaper subclass for each text layout
1060 : * technology (uniscribe, core text, harfbuzz,....) we support.
1061 : *
1062 : * The shaper is responsible for setting up glyph data in gfxTextRuns.
1063 : *
1064 : * A generic, platform-independent shaper relies only on the standard
1065 : * gfxFont interface and can work with any concrete subclass of gfxFont.
1066 : *
1067 : * Platform-specific implementations designed to interface to platform
1068 : * shaping APIs such as Uniscribe or CoreText may rely on features of a
1069 : * specific font subclass to access native font references
1070 : * (such as CTFont, HFONT, DWriteFont, etc).
1071 : */
1072 :
1073 : class gfxFontShaper {
1074 : public:
1075 0 : gfxFontShaper(gfxFont *aFont)
1076 0 : : mFont(aFont)
1077 : {
1078 0 : NS_ASSERTION(aFont, "shaper requires a valid font!");
1079 0 : }
1080 :
1081 0 : virtual ~gfxFontShaper() { }
1082 :
1083 : virtual bool ShapeWord(gfxContext *aContext,
1084 : gfxShapedWord *aShapedWord,
1085 : const PRUnichar *aText) = 0;
1086 :
1087 0 : gfxFont *GetFont() const { return mFont; }
1088 :
1089 : protected:
1090 : // the font this shaper is working with
1091 : gfxFont * mFont;
1092 : };
1093 :
1094 : /* a SPECIFIC single font family */
1095 : class THEBES_API gfxFont {
1096 : public:
1097 0 : nsrefcnt AddRef(void) {
1098 0 : NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
1099 0 : if (mExpirationState.IsTracked()) {
1100 0 : gfxFontCache::GetCache()->RemoveObject(this);
1101 : }
1102 0 : ++mRefCnt;
1103 0 : NS_LOG_ADDREF(this, mRefCnt, "gfxFont", sizeof(*this));
1104 0 : return mRefCnt;
1105 : }
1106 0 : nsrefcnt Release(void) {
1107 0 : NS_PRECONDITION(0 != mRefCnt, "dup release");
1108 0 : --mRefCnt;
1109 0 : NS_LOG_RELEASE(this, mRefCnt, "gfxFont");
1110 0 : if (mRefCnt == 0) {
1111 0 : NotifyReleased();
1112 : // |this| may have been deleted.
1113 0 : return 0;
1114 : }
1115 0 : return mRefCnt;
1116 : }
1117 :
1118 0 : PRInt32 GetRefCount() { return mRefCnt; }
1119 :
1120 : // options to specify the kind of AA to be used when creating a font
1121 : typedef enum {
1122 : kAntialiasDefault,
1123 : kAntialiasNone,
1124 : kAntialiasGrayscale,
1125 : kAntialiasSubpixel
1126 : } AntialiasOption;
1127 :
1128 : // Options for how the text should be drawn
1129 : typedef enum {
1130 : // GLYPH_FILL and GLYPH_STROKE draw into the current context
1131 : // and may be used together with bitwise OR.
1132 : GLYPH_FILL = 1,
1133 : // Note: using GLYPH_STROKE will destroy the current path.
1134 : GLYPH_STROKE = 2,
1135 : // Appends glyphs to the current path. Can NOT be used with
1136 : // GLYPH_FILL or GLYPH_STROKE.
1137 : GLYPH_PATH = 4
1138 : } DrawMode;
1139 :
1140 : protected:
1141 : nsAutoRefCnt mRefCnt;
1142 : cairo_scaled_font_t *mScaledFont;
1143 :
1144 0 : void NotifyReleased() {
1145 0 : gfxFontCache *cache = gfxFontCache::GetCache();
1146 0 : if (cache) {
1147 : // Don't delete just yet; return the object to the cache for
1148 : // possibly recycling within some time limit
1149 0 : cache->NotifyReleased(this);
1150 : } else {
1151 : // The cache may have already been shut down.
1152 0 : delete this;
1153 : }
1154 0 : }
1155 :
1156 : gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
1157 : AntialiasOption anAAOption = kAntialiasDefault,
1158 : cairo_scaled_font_t *aScaledFont = nsnull);
1159 :
1160 : public:
1161 : virtual ~gfxFont();
1162 :
1163 0 : bool Valid() const {
1164 0 : return mIsValid;
1165 : }
1166 :
1167 : // options for the kind of bounding box to return from measurement
1168 : typedef enum {
1169 : LOOSE_INK_EXTENTS,
1170 : // A box that encloses all the painted pixels, and may
1171 : // include sidebearings and/or additional ascent/descent
1172 : // within the glyph cell even if the ink is smaller.
1173 : TIGHT_INK_EXTENTS,
1174 : // A box that tightly encloses all the painted pixels
1175 : // (although actually on Windows, at least, it may be
1176 : // slightly larger than strictly necessary because
1177 : // we can't get precise extents with ClearType).
1178 : TIGHT_HINTED_OUTLINE_EXTENTS
1179 : // A box that tightly encloses the glyph outline,
1180 : // ignoring possible antialiasing pixels that extend
1181 : // beyond this.
1182 : // NOTE: The default implementation of gfxFont::Measure(),
1183 : // which works with the glyph extents cache, does not
1184 : // differentiate between this and TIGHT_INK_EXTENTS.
1185 : // Whether the distinction is important depends on the
1186 : // antialiasing behavior of the platform; currently the
1187 : // distinction is only implemented in the gfxWindowsFont
1188 : // subclass, because of ClearType's tendency to paint
1189 : // outside the hinted outline.
1190 : // Also NOTE: it is relatively expensive to request this,
1191 : // as it does not use cached glyph extents in the font.
1192 : } BoundingBoxType;
1193 :
1194 0 : const nsString& GetName() const { return mFontEntry->Name(); }
1195 0 : const gfxFontStyle *GetStyle() const { return &mStyle; }
1196 :
1197 : cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; }
1198 :
1199 0 : virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption) {
1200 : // platforms where this actually matters should override
1201 0 : return nsnull;
1202 : }
1203 :
1204 0 : virtual gfxFloat GetAdjustedSize() {
1205 0 : return mAdjustedSize > 0.0 ? mAdjustedSize : mStyle.size;
1206 : }
1207 :
1208 0 : float FUnitsToDevUnitsFactor() const {
1209 : // check this was set up during font initialization
1210 0 : NS_ASSERTION(mFUnitsConvFactor > 0.0f, "mFUnitsConvFactor not valid");
1211 0 : return mFUnitsConvFactor;
1212 : }
1213 :
1214 : // check whether this is an sfnt we can potentially use with harfbuzz
1215 : bool FontCanSupportHarfBuzz() {
1216 : return mFontEntry->HasCmapTable();
1217 : }
1218 :
1219 : #ifdef MOZ_GRAPHITE
1220 : // check whether this is an sfnt we can potentially use with Graphite
1221 0 : bool FontCanSupportGraphite() {
1222 0 : return mFontEntry->HasGraphiteTables();
1223 : }
1224 : #endif
1225 :
1226 : // Access to raw font table data (needed for Harfbuzz):
1227 : // returns a pointer to data owned by the fontEntry or the OS,
1228 : // which will remain valid until released.
1229 : //
1230 : // Default implementations forward to the font entry,
1231 : // and maintain a shared table.
1232 : //
1233 : // Subclasses should override this if they can provide more efficient
1234 : // access than getting tables with mFontEntry->GetFontTable() and sharing
1235 : // them via the entry.
1236 : //
1237 : // Get pointer to a specific font table, or NULL if
1238 : // the table doesn't exist in the font
1239 : virtual hb_blob_t *GetFontTable(PRUint32 aTag);
1240 :
1241 : // Subclasses may choose to look up glyph ids for characters.
1242 : // If they do not override this, gfxHarfBuzzShaper will fetch the cmap
1243 : // table and use that.
1244 0 : virtual bool ProvidesGetGlyph() const {
1245 0 : return false;
1246 : }
1247 : // Map unicode character to glyph ID.
1248 : // Only used if ProvidesGetGlyph() returns true.
1249 0 : virtual PRUint32 GetGlyph(PRUint32 unicode, PRUint32 variation_selector) {
1250 0 : return 0;
1251 : }
1252 :
1253 : // subclasses may provide (possibly hinted) glyph widths (in font units);
1254 : // if they do not override this, harfbuzz will use unhinted widths
1255 : // derived from the font tables
1256 0 : virtual bool ProvidesGlyphWidths() {
1257 0 : return false;
1258 : }
1259 :
1260 : // The return value is interpreted as a horizontal advance in 16.16 fixed
1261 : // point format.
1262 0 : virtual PRInt32 GetGlyphWidth(gfxContext *aCtx, PRUint16 aGID) {
1263 0 : return -1;
1264 : }
1265 :
1266 : gfxFloat SynthesizeSpaceWidth(PRUint32 aCh);
1267 :
1268 : // Font metrics
1269 : struct Metrics {
1270 : gfxFloat xHeight;
1271 : gfxFloat superscriptOffset;
1272 : gfxFloat subscriptOffset;
1273 : gfxFloat strikeoutSize;
1274 : gfxFloat strikeoutOffset;
1275 : gfxFloat underlineSize;
1276 : gfxFloat underlineOffset;
1277 :
1278 : gfxFloat internalLeading;
1279 : gfxFloat externalLeading;
1280 :
1281 : gfxFloat emHeight;
1282 : gfxFloat emAscent;
1283 : gfxFloat emDescent;
1284 : gfxFloat maxHeight;
1285 : gfxFloat maxAscent;
1286 : gfxFloat maxDescent;
1287 : gfxFloat maxAdvance;
1288 :
1289 : gfxFloat aveCharWidth;
1290 : gfxFloat spaceWidth;
1291 : gfxFloat zeroOrAveCharWidth; // width of '0', or if there is
1292 : // no '0' glyph in this font,
1293 : // equal to .aveCharWidth
1294 : };
1295 : virtual const gfxFont::Metrics& GetMetrics() = 0;
1296 :
1297 : /**
1298 : * We let layout specify spacing on either side of any
1299 : * character. We need to specify both before and after
1300 : * spacing so that substring measurement can do the right things.
1301 : * These values are in appunits. They're always an integral number of
1302 : * appunits, but we specify them in floats in case very large spacing
1303 : * values are required.
1304 : */
1305 0 : struct Spacing {
1306 : gfxFloat mBefore;
1307 : gfxFloat mAfter;
1308 : };
1309 : /**
1310 : * Metrics for a particular string
1311 : */
1312 : struct THEBES_API RunMetrics {
1313 0 : RunMetrics() {
1314 0 : mAdvanceWidth = mAscent = mDescent = 0.0;
1315 0 : mBoundingBox = gfxRect(0,0,0,0);
1316 0 : }
1317 :
1318 : void CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft);
1319 :
1320 : // can be negative (partly due to negative spacing).
1321 : // Advance widths should be additive: the advance width of the
1322 : // (offset1, length1) plus the advance width of (offset1 + length1,
1323 : // length2) should be the advance width of (offset1, length1 + length2)
1324 : gfxFloat mAdvanceWidth;
1325 :
1326 : // For zero-width substrings, these must be zero!
1327 : gfxFloat mAscent; // always non-negative
1328 : gfxFloat mDescent; // always non-negative
1329 :
1330 : // Bounding box that is guaranteed to include everything drawn.
1331 : // If a tight boundingBox was requested when these metrics were
1332 : // generated, this will tightly wrap the glyphs, otherwise it is
1333 : // "loose" and may be larger than the true bounding box.
1334 : // Coordinates are relative to the baseline left origin, so typically
1335 : // mBoundingBox.y == -mAscent
1336 : gfxRect mBoundingBox;
1337 : };
1338 :
1339 : /**
1340 : * Draw a series of glyphs to aContext. The direction of aTextRun must
1341 : * be honoured.
1342 : * @param aStart the first character to draw
1343 : * @param aEnd draw characters up to here
1344 : * @param aBaselineOrigin the baseline origin; the left end of the baseline
1345 : * for LTR textruns, the right end of the baseline for RTL textruns. On return,
1346 : * this should be updated to the other end of the baseline. In application
1347 : * units, really!
1348 : * @param aSpacing spacing to insert before and after characters (for RTL
1349 : * glyphs, before-spacing is inserted to the right of characters). There
1350 : * are aEnd - aStart elements in this array, unless it's null to indicate
1351 : * that there is no spacing.
1352 : * @param aDrawMode specifies whether the fill or stroke of the glyph should be
1353 : * drawn, or if it should be drawn into the current path
1354 : *
1355 : * Callers guarantee:
1356 : * -- aStart and aEnd are aligned to cluster and ligature boundaries
1357 : * -- all glyphs use this font
1358 : *
1359 : * The default implementation builds a cairo glyph array and
1360 : * calls cairo_show_glyphs or cairo_glyph_path.
1361 : */
1362 : virtual void Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
1363 : gfxContext *aContext, DrawMode aDrawMode, gfxPoint *aBaselineOrigin,
1364 : Spacing *aSpacing, gfxPattern *aStrokePattern);
1365 :
1366 : /**
1367 : * Measure a run of characters. See gfxTextRun::Metrics.
1368 : * @param aTight if false, then return the union of the glyph extents
1369 : * with the font-box for the characters (the rectangle with x=0,width=
1370 : * the advance width for the character run,y=-(font ascent), and height=
1371 : * font ascent + font descent). Otherwise, we must return as tight as possible
1372 : * an approximation to the area actually painted by glyphs.
1373 : * @param aContextForTightBoundingBox when aTight is true, this must
1374 : * be non-null.
1375 : * @param aSpacing spacing to insert before and after glyphs. The bounding box
1376 : * need not include the spacing itself, but the spacing affects the glyph
1377 : * positions. null if there is no spacing.
1378 : *
1379 : * Callers guarantee:
1380 : * -- aStart and aEnd are aligned to cluster and ligature boundaries
1381 : * -- all glyphs use this font
1382 : *
1383 : * The default implementation just uses font metrics and aTextRun's
1384 : * advances, and assumes no characters fall outside the font box. In
1385 : * general this is insufficient, because that assumption is not always true.
1386 : */
1387 : virtual RunMetrics Measure(gfxTextRun *aTextRun,
1388 : PRUint32 aStart, PRUint32 aEnd,
1389 : BoundingBoxType aBoundingBoxType,
1390 : gfxContext *aContextForTightBoundingBox,
1391 : Spacing *aSpacing);
1392 : /**
1393 : * Line breaks have been changed at the beginning and/or end of a substring
1394 : * of the text. Reshaping may be required; glyph updating is permitted.
1395 : * @return true if anything was changed, false otherwise
1396 : */
1397 : bool NotifyLineBreaksChanged(gfxTextRun *aTextRun,
1398 : PRUint32 aStart, PRUint32 aLength)
1399 : { return false; }
1400 :
1401 : // Expiration tracking
1402 0 : nsExpirationState *GetExpirationState() { return &mExpirationState; }
1403 :
1404 : // Get the glyphID of a space
1405 : virtual PRUint32 GetSpaceGlyph() = 0;
1406 :
1407 : gfxGlyphExtents *GetOrCreateGlyphExtents(PRUint32 aAppUnitsPerDevUnit);
1408 :
1409 : // You need to call SetupCairoFont on the aCR just before calling this
1410 : virtual void SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID,
1411 : bool aNeedTight, gfxGlyphExtents *aExtents);
1412 :
1413 : // This is called by the default Draw() implementation above.
1414 : virtual bool SetupCairoFont(gfxContext *aContext) = 0;
1415 :
1416 0 : bool IsSyntheticBold() { return mApplySyntheticBold; }
1417 :
1418 : // Amount by which synthetic bold "fattens" the glyphs: 1/16 of the em-size
1419 0 : gfxFloat GetSyntheticBoldOffset() {
1420 0 : return GetAdjustedSize() * (1.0 / 16.0);
1421 : }
1422 :
1423 0 : gfxFontEntry *GetFontEntry() { return mFontEntry.get(); }
1424 0 : bool HasCharacter(PRUint32 ch) {
1425 0 : if (!mIsValid)
1426 0 : return false;
1427 0 : return mFontEntry->HasCharacter(ch);
1428 : }
1429 :
1430 : PRUint16 GetUVSGlyph(PRUint32 aCh, PRUint32 aVS) {
1431 : if (!mIsValid) {
1432 : return 0;
1433 : }
1434 : return mFontEntry->GetUVSGlyph(aCh, aVS);
1435 : }
1436 :
1437 : // call the (virtual) InitTextRun method to do glyph generation/shaping,
1438 : // limiting the length of text passed by processing the run in multiple
1439 : // segments if necessary
1440 : template<typename T>
1441 : bool SplitAndInitTextRun(gfxContext *aContext,
1442 : gfxTextRun *aTextRun,
1443 : const T *aString,
1444 : PRUint32 aRunStart,
1445 : PRUint32 aRunLength,
1446 : PRInt32 aRunScript);
1447 :
1448 : // Get a ShapedWord representing the given text (either 8- or 16-bit)
1449 : // for use in setting up a gfxTextRun.
1450 : template<typename T>
1451 : gfxShapedWord* GetShapedWord(gfxContext *aContext,
1452 : const T *aText,
1453 : PRUint32 aLength,
1454 : PRUint32 aHash,
1455 : PRInt32 aRunScript,
1456 : PRInt32 aAppUnitsPerDevUnit,
1457 : PRUint32 aFlags);
1458 :
1459 : // Ensure the ShapedWord cache is initialized. This MUST be called before
1460 : // any attempt to use GetShapedWord().
1461 0 : void InitWordCache() {
1462 0 : if (!mWordCache.IsInitialized()) {
1463 0 : mWordCache.Init();
1464 : }
1465 0 : }
1466 :
1467 : // Called by the gfxFontCache timer to increment the age of all the words,
1468 : // so that they'll expire after a sufficient period of non-use
1469 0 : void AgeCachedWords() {
1470 0 : if (mWordCache.IsInitialized()) {
1471 0 : (void)mWordCache.EnumerateEntries(AgeCacheEntry, this);
1472 : }
1473 0 : }
1474 :
1475 : // Discard all cached word records; called on memory-pressure notification.
1476 0 : void ClearCachedWords() {
1477 0 : if (mWordCache.IsInitialized()) {
1478 0 : mWordCache.Clear();
1479 : }
1480 0 : }
1481 :
1482 : protected:
1483 : // Call the appropriate shaper to generate glyphs for aText and store
1484 : // them into aShapedWord.
1485 : // The length of the text is aShapedWord->Length().
1486 : virtual bool ShapeWord(gfxContext *aContext,
1487 : gfxShapedWord *aShapedWord,
1488 : const PRUnichar *aText,
1489 : bool aPreferPlatformShaping = false);
1490 :
1491 : nsRefPtr<gfxFontEntry> mFontEntry;
1492 :
1493 : struct CacheHashKey {
1494 : union {
1495 : const PRUint8 *mSingle;
1496 : const PRUnichar *mDouble;
1497 : } mText;
1498 : PRUint32 mLength;
1499 : PRUint32 mFlags;
1500 : PRInt32 mScript;
1501 : PRInt32 mAppUnitsPerDevUnit;
1502 : PLDHashNumber mHashKey;
1503 : bool mTextIs8Bit;
1504 :
1505 0 : CacheHashKey(const PRUint8 *aText, PRUint32 aLength,
1506 : PRUint32 aStringHash,
1507 : PRInt32 aScriptCode, PRInt32 aAppUnitsPerDevUnit,
1508 : PRUint32 aFlags)
1509 : : mLength(aLength),
1510 : mFlags(aFlags),
1511 : mScript(aScriptCode),
1512 : mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
1513 : mHashKey(aStringHash + aScriptCode +
1514 : aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000),
1515 0 : mTextIs8Bit(true)
1516 : {
1517 0 : NS_ASSERTION(aFlags & gfxTextRunFactory::TEXT_IS_8BIT,
1518 : "8-bit flag should have been set");
1519 0 : mText.mSingle = aText;
1520 0 : }
1521 :
1522 0 : CacheHashKey(const PRUnichar *aText, PRUint32 aLength,
1523 : PRUint32 aStringHash,
1524 : PRInt32 aScriptCode, PRInt32 aAppUnitsPerDevUnit,
1525 : PRUint32 aFlags)
1526 : : mLength(aLength),
1527 : mFlags(aFlags),
1528 : mScript(aScriptCode),
1529 : mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
1530 : mHashKey(aStringHash + aScriptCode +
1531 : aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000),
1532 0 : mTextIs8Bit(false)
1533 : {
1534 : // We can NOT assert that TEXT_IS_8BIT is false in aFlags here,
1535 : // because this might be an 8bit-only word from a 16-bit textrun,
1536 : // in which case the text we're passed is still in 16-bit form,
1537 : // and we'll have to use an 8-to-16bit comparison in KeyEquals.
1538 0 : mText.mDouble = aText;
1539 0 : }
1540 : };
1541 :
1542 : class CacheHashEntry : public PLDHashEntryHdr {
1543 : public:
1544 : typedef const CacheHashKey &KeyType;
1545 : typedef const CacheHashKey *KeyTypePointer;
1546 :
1547 : // When constructing a new entry in the hashtable, the caller of Put()
1548 : // will fill us in.
1549 0 : CacheHashEntry(KeyTypePointer aKey) { }
1550 : CacheHashEntry(const CacheHashEntry& toCopy) { NS_ERROR("Should not be called"); }
1551 0 : ~CacheHashEntry() { }
1552 :
1553 : bool KeyEquals(const KeyTypePointer aKey) const;
1554 :
1555 0 : static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
1556 :
1557 0 : static PLDHashNumber HashKey(const KeyTypePointer aKey) {
1558 0 : return aKey->mHashKey;
1559 : }
1560 :
1561 : enum { ALLOW_MEMMOVE = true };
1562 :
1563 : nsAutoPtr<gfxShapedWord> mShapedWord;
1564 : };
1565 :
1566 : nsTHashtable<CacheHashEntry> mWordCache;
1567 :
1568 : static PLDHashOperator AgeCacheEntry(CacheHashEntry *aEntry, void *aUserData);
1569 : static const PRUint32 kShapedWordCacheMaxAge = 3;
1570 :
1571 : bool mIsValid;
1572 :
1573 : // use synthetic bolding for environments where this is not supported
1574 : // by the platform
1575 : bool mApplySyntheticBold;
1576 :
1577 : nsExpirationState mExpirationState;
1578 : gfxFontStyle mStyle;
1579 : nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray;
1580 :
1581 : gfxFloat mAdjustedSize;
1582 :
1583 : float mFUnitsConvFactor; // conversion factor from font units to dev units
1584 :
1585 : // the AA setting requested for this font - may affect glyph bounds
1586 : AntialiasOption mAntialiasOption;
1587 :
1588 : // a copy of the font without antialiasing, if needed for separate
1589 : // measurement by mathml code
1590 : nsAutoPtr<gfxFont> mNonAAFont;
1591 :
1592 : // we may switch between these shapers on the fly, based on the script
1593 : // of the text run being shaped
1594 : nsAutoPtr<gfxFontShaper> mPlatformShaper;
1595 : nsAutoPtr<gfxFontShaper> mHarfBuzzShaper;
1596 : #ifdef MOZ_GRAPHITE
1597 : nsAutoPtr<gfxFontShaper> mGraphiteShaper;
1598 : #endif
1599 :
1600 : // Create a default platform text shaper for this font.
1601 : // (TODO: This should become pure virtual once all font backends have
1602 : // been updated.)
1603 0 : virtual void CreatePlatformShaper() { }
1604 :
1605 : // Helper for subclasses that want to initialize standard metrics from the
1606 : // tables of sfnt (TrueType/OpenType) fonts.
1607 : // This will use mFUnitsConvFactor if it is already set, else compute it
1608 : // from mAdjustedSize and the unitsPerEm in the font's 'head' table.
1609 : // Returns TRUE and sets mIsValid=TRUE if successful;
1610 : // Returns TRUE but leaves mIsValid=FALSE if the font seems to be broken.
1611 : // Returns FALSE if the font does not appear to be an sfnt at all,
1612 : // and should be handled (if possible) using other APIs.
1613 : bool InitMetricsFromSfntTables(Metrics& aMetrics);
1614 :
1615 : // Helper to calculate various derived metrics from the results of
1616 : // InitMetricsFromSfntTables or equivalent platform code
1617 : void CalculateDerivedMetrics(Metrics& aMetrics);
1618 :
1619 : // some fonts have bad metrics, this method sanitize them.
1620 : // if this font has bad underline offset, aIsBadUnderlineFont should be true.
1621 : void SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont);
1622 :
1623 : // Bug 674909. When synthetic bolding text by drawing twice, need to
1624 : // render using a pixel offset in device pixels, otherwise text
1625 : // doesn't appear bolded, it appears as if a bad text shadow exists
1626 : // when a non-identity transform exists. Use an offset factor so that
1627 : // the second draw occurs at a constant offset in device pixels.
1628 : // This helper calculates the scale factor we need to apply to the
1629 : // synthetic-bold offset.
1630 : static double CalcXScale(gfxContext *aContext);
1631 : };
1632 :
1633 : // proportion of ascent used for x-height, if unable to read value from font
1634 : #define DEFAULT_XHEIGHT_FACTOR 0.56f
1635 :
1636 : /*
1637 : * gfxShapedWord stores a list of zero or more glyphs for each character. For each
1638 : * glyph we store the glyph ID, the advance, and possibly an xoffset and yoffset.
1639 : * The idea is that a string is rendered by a loop that draws each glyph
1640 : * at its designated offset from the current point, then advances the current
1641 : * point by the glyph's advance in the direction of the textrun (LTR or RTL).
1642 : * Each glyph advance is always rounded to the nearest appunit; this ensures
1643 : * consistent results when dividing the text in a textrun into multiple text
1644 : * frames (frame boundaries are always aligned to appunits). We optimize
1645 : * for the case where a character has a single glyph and zero xoffset and yoffset,
1646 : * and the glyph ID and advance are in a reasonable range so we can pack all
1647 : * necessary data into 32 bits.
1648 : *
1649 : * This glyph data is copied into gfxTextRuns as needed from the cache of
1650 : * ShapedWords associated with each gfxFont instance.
1651 : *
1652 : * gfxTextRun methods that measure or draw substrings will associate all the
1653 : * glyphs in a cluster with the first character of the cluster; if that character
1654 : * is in the substring, the glyphs will be measured or drawn, otherwise they
1655 : * won't.
1656 : */
1657 : class gfxShapedWord
1658 0 : {
1659 : public:
1660 : static const PRUint32 kMaxLength = 0x7fff;
1661 :
1662 : // Create a ShapedWord that can hold glyphs for aLength characters,
1663 : // with mCharacterGlyphs sized appropriately.
1664 : //
1665 : // Returns null on allocation failure (does NOT use infallible alloc)
1666 : // so caller must check for success.
1667 : //
1668 : // This does NOT perform shaping, so the returned word contains no
1669 : // glyph data; the caller must call gfxFont::Shape() with appropriate
1670 : // parameters to set up the glyphs.
1671 0 : static gfxShapedWord* Create(const PRUint8 *aText, PRUint32 aLength,
1672 : PRInt32 aRunScript,
1673 : PRInt32 aAppUnitsPerDevUnit,
1674 : PRUint32 aFlags) {
1675 0 : NS_ASSERTION(aLength <= kMaxLength, "excessive length for gfxShapedWord!");
1676 :
1677 : // Compute size needed including the mCharacterGlyphs array
1678 : // and a copy of the original text
1679 : PRUint32 size =
1680 : offsetof(gfxShapedWord, mCharacterGlyphs) +
1681 0 : aLength * (sizeof(CompressedGlyph) + sizeof(PRUint8));
1682 0 : void *storage = moz_malloc(size);
1683 0 : if (!storage) {
1684 0 : return nsnull;
1685 : }
1686 :
1687 : // Construct in the pre-allocated storage, using placement new
1688 : return new (storage) gfxShapedWord(aText, aLength, aRunScript,
1689 0 : aAppUnitsPerDevUnit, aFlags);
1690 : }
1691 :
1692 0 : static gfxShapedWord* Create(const PRUnichar *aText, PRUint32 aLength,
1693 : PRInt32 aRunScript,
1694 : PRInt32 aAppUnitsPerDevUnit,
1695 : PRUint32 aFlags) {
1696 0 : NS_ASSERTION(aLength <= kMaxLength, "excessive length for gfxShapedWord!");
1697 :
1698 : // In the 16-bit version of Create, if the TEXT_IS_8BIT flag is set,
1699 : // then we convert the text to an 8-bit version and call the 8-bit
1700 : // Create function instead.
1701 0 : if (aFlags & gfxTextRunFactory::TEXT_IS_8BIT) {
1702 0 : nsCAutoString narrowText;
1703 0 : LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength),
1704 0 : narrowText);
1705 0 : return Create((const PRUint8*)(narrowText.BeginReading()),
1706 0 : aLength, aRunScript, aAppUnitsPerDevUnit, aFlags);
1707 : }
1708 :
1709 : PRUint32 size =
1710 : offsetof(gfxShapedWord, mCharacterGlyphs) +
1711 0 : aLength * (sizeof(CompressedGlyph) + sizeof(PRUnichar));
1712 0 : void *storage = moz_malloc(size);
1713 0 : if (!storage) {
1714 0 : return nsnull;
1715 : }
1716 :
1717 : return new (storage) gfxShapedWord(aText, aLength, aRunScript,
1718 0 : aAppUnitsPerDevUnit, aFlags);
1719 : }
1720 :
1721 : // Override operator delete to properly free the object that was
1722 : // allocated via moz_malloc.
1723 0 : void operator delete(void* p) {
1724 0 : moz_free(p);
1725 0 : }
1726 :
1727 : /**
1728 : * This class records the information associated with a character in the
1729 : * input string. It's optimized for the case where there is one glyph
1730 : * representing that character alone.
1731 : *
1732 : * A character can have zero or more associated glyphs. Each glyph
1733 : * has an advance width and an x and y offset.
1734 : * A character may be the start of a cluster.
1735 : * A character may be the start of a ligature group.
1736 : * A character can be "missing", indicating that the system is unable
1737 : * to render the character.
1738 : *
1739 : * All characters in a ligature group conceptually share all the glyphs
1740 : * associated with the characters in a group.
1741 : */
1742 : class CompressedGlyph {
1743 : public:
1744 0 : CompressedGlyph() { mValue = 0; }
1745 :
1746 : enum {
1747 : // Indicates that a cluster and ligature group starts at this
1748 : // character; this character has a single glyph with a reasonable
1749 : // advance and zero offsets. A "reasonable" advance
1750 : // is one that fits in the available bits (currently 12) (specified
1751 : // in appunits).
1752 : FLAG_IS_SIMPLE_GLYPH = 0x80000000U,
1753 :
1754 : // Indicates whether a linebreak is allowed before this character;
1755 : // this is a two-bit field that holds a FLAG_BREAK_TYPE_xxx value
1756 : // indicating the kind of linebreak (if any) allowed here.
1757 : FLAGS_CAN_BREAK_BEFORE = 0x60000000U,
1758 :
1759 : FLAGS_CAN_BREAK_SHIFT = 29,
1760 : FLAG_BREAK_TYPE_NONE = 0,
1761 : FLAG_BREAK_TYPE_NORMAL = 1,
1762 : FLAG_BREAK_TYPE_HYPHEN = 2,
1763 :
1764 : FLAG_CHAR_IS_SPACE = 0x10000000U,
1765 :
1766 : // The advance is stored in appunits
1767 : ADVANCE_MASK = 0x0FFF0000U,
1768 : ADVANCE_SHIFT = 16,
1769 :
1770 : GLYPH_MASK = 0x0000FFFFU,
1771 :
1772 : // Non-simple glyphs may or may not have glyph data in the
1773 : // corresponding mDetailedGlyphs entry. They have the following
1774 : // flag bits:
1775 :
1776 : // When NOT set, indicates that this character corresponds to a
1777 : // missing glyph and should be skipped (or possibly, render the character
1778 : // Unicode value in some special way). If there are glyphs,
1779 : // the mGlyphID is actually the UTF16 character code. The bit is
1780 : // inverted so we can memset the array to zero to indicate all missing.
1781 : FLAG_NOT_MISSING = 0x01,
1782 : FLAG_NOT_CLUSTER_START = 0x02,
1783 : FLAG_NOT_LIGATURE_GROUP_START = 0x04,
1784 :
1785 : FLAG_CHAR_IS_TAB = 0x08,
1786 : FLAG_CHAR_IS_NEWLINE = 0x10,
1787 : FLAG_CHAR_IS_LOW_SURROGATE = 0x20,
1788 : CHAR_IDENTITY_FLAGS_MASK = 0x38,
1789 :
1790 : GLYPH_COUNT_MASK = 0x00FFFF00U,
1791 : GLYPH_COUNT_SHIFT = 8
1792 : };
1793 :
1794 : // "Simple glyphs" have a simple glyph ID, simple advance and their
1795 : // x and y offsets are zero. Also the glyph extents do not overflow
1796 : // the font-box defined by the font ascent, descent and glyph advance width.
1797 : // These case is optimized to avoid storing DetailedGlyphs.
1798 :
1799 : // Returns true if the glyph ID aGlyph fits into the compressed representation
1800 0 : static bool IsSimpleGlyphID(PRUint32 aGlyph) {
1801 0 : return (aGlyph & GLYPH_MASK) == aGlyph;
1802 : }
1803 : // Returns true if the advance aAdvance fits into the compressed representation.
1804 : // aAdvance is in appunits.
1805 0 : static bool IsSimpleAdvance(PRUint32 aAdvance) {
1806 0 : return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
1807 : }
1808 :
1809 0 : bool IsSimpleGlyph() const { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; }
1810 0 : PRUint32 GetSimpleAdvance() const { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
1811 0 : PRUint32 GetSimpleGlyph() const { return mValue & GLYPH_MASK; }
1812 :
1813 0 : bool IsMissing() const { return (mValue & (FLAG_NOT_MISSING|FLAG_IS_SIMPLE_GLYPH)) == 0; }
1814 0 : bool IsClusterStart() const {
1815 0 : return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_CLUSTER_START);
1816 : }
1817 0 : bool IsLigatureGroupStart() const {
1818 0 : return (mValue & FLAG_IS_SIMPLE_GLYPH) || !(mValue & FLAG_NOT_LIGATURE_GROUP_START);
1819 : }
1820 0 : bool IsLigatureContinuation() const {
1821 : return (mValue & FLAG_IS_SIMPLE_GLYPH) == 0 &&
1822 : (mValue & (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING)) ==
1823 0 : (FLAG_NOT_LIGATURE_GROUP_START | FLAG_NOT_MISSING);
1824 : }
1825 :
1826 : // Return true if the original character was a normal (breakable,
1827 : // trimmable) space (U+0020). Not true for other characters that
1828 : // may happen to map to the space glyph (U+00A0).
1829 0 : bool CharIsSpace() const {
1830 0 : return (mValue & FLAG_CHAR_IS_SPACE) != 0;
1831 : }
1832 :
1833 : bool CharIsTab() const {
1834 : return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_TAB) != 0;
1835 : }
1836 : bool CharIsNewline() const {
1837 : return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_NEWLINE) != 0;
1838 : }
1839 : bool CharIsLowSurrogate() const {
1840 : return !IsSimpleGlyph() && (mValue & FLAG_CHAR_IS_LOW_SURROGATE) != 0;
1841 : }
1842 :
1843 0 : PRUint32 CharIdentityFlags() const {
1844 0 : return IsSimpleGlyph() ? 0 : (mValue & CHAR_IDENTITY_FLAGS_MASK);
1845 : }
1846 :
1847 0 : void SetClusterStart(bool aIsClusterStart) {
1848 0 : NS_ASSERTION(!IsSimpleGlyph(),
1849 : "can't call SetClusterStart on simple glyphs");
1850 0 : if (aIsClusterStart) {
1851 0 : mValue &= ~FLAG_NOT_CLUSTER_START;
1852 : } else {
1853 0 : mValue |= FLAG_NOT_CLUSTER_START;
1854 : }
1855 0 : }
1856 :
1857 0 : PRUint8 CanBreakBefore() const {
1858 0 : return (mValue & FLAGS_CAN_BREAK_BEFORE) >> FLAGS_CAN_BREAK_SHIFT;
1859 : }
1860 : // Returns FLAGS_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
1861 0 : PRUint32 SetCanBreakBefore(PRUint8 aCanBreakBefore) {
1862 0 : NS_ASSERTION(aCanBreakBefore <= 2,
1863 : "Bogus break-before value!");
1864 0 : PRUint32 breakMask = (PRUint32(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT);
1865 0 : PRUint32 toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE);
1866 0 : mValue ^= toggle;
1867 0 : return toggle;
1868 : }
1869 :
1870 0 : CompressedGlyph& SetSimpleGlyph(PRUint32 aAdvanceAppUnits, PRUint32 aGlyph) {
1871 0 : NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow");
1872 0 : NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
1873 0 : NS_ASSERTION(!CharIdentityFlags(), "Char identity flags lost");
1874 : mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
1875 : FLAG_IS_SIMPLE_GLYPH |
1876 0 : (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
1877 0 : return *this;
1878 : }
1879 0 : CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart,
1880 : PRUint32 aGlyphCount) {
1881 : mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
1882 : FLAG_NOT_MISSING |
1883 0 : CharIdentityFlags() |
1884 : (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
1885 : (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
1886 0 : (aGlyphCount << GLYPH_COUNT_SHIFT);
1887 0 : return *this;
1888 : }
1889 : /**
1890 : * Missing glyphs are treated as ligature group starts; don't mess with
1891 : * the cluster-start flag (see bugs 618870 and 619286).
1892 : */
1893 0 : CompressedGlyph& SetMissing(PRUint32 aGlyphCount) {
1894 : mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_NOT_CLUSTER_START |
1895 : FLAG_CHAR_IS_SPACE)) |
1896 0 : CharIdentityFlags() |
1897 0 : (aGlyphCount << GLYPH_COUNT_SHIFT);
1898 0 : return *this;
1899 : }
1900 0 : PRUint32 GetGlyphCount() const {
1901 0 : NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
1902 0 : return (mValue & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT;
1903 : }
1904 :
1905 0 : void SetIsSpace() {
1906 0 : mValue |= FLAG_CHAR_IS_SPACE;
1907 0 : }
1908 0 : void SetIsTab() {
1909 0 : NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
1910 0 : mValue |= FLAG_CHAR_IS_TAB;
1911 0 : }
1912 0 : void SetIsNewline() {
1913 0 : NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
1914 0 : mValue |= FLAG_CHAR_IS_NEWLINE;
1915 0 : }
1916 0 : void SetIsLowSurrogate() {
1917 0 : NS_ASSERTION(!IsSimpleGlyph(), "Expected non-simple-glyph");
1918 0 : mValue |= FLAG_CHAR_IS_LOW_SURROGATE;
1919 0 : }
1920 :
1921 : private:
1922 : PRUint32 mValue;
1923 : };
1924 :
1925 : /**
1926 : * When the glyphs for a character don't fit into a CompressedGlyph record
1927 : * in SimpleGlyph format, we use an array of DetailedGlyphs instead.
1928 : */
1929 0 : struct DetailedGlyph {
1930 : /** The glyphID, or the Unicode character
1931 : * if this is a missing glyph */
1932 : PRUint32 mGlyphID;
1933 : /** The advance, x-offset and y-offset of the glyph, in appunits
1934 : * mAdvance is in the text direction (RTL or LTR)
1935 : * mXOffset is always from left to right
1936 : * mYOffset is always from top to bottom */
1937 : PRInt32 mAdvance;
1938 : float mXOffset, mYOffset;
1939 : };
1940 :
1941 0 : bool IsClusterStart(PRUint32 aPos) {
1942 0 : NS_ASSERTION(aPos < Length(), "aPos out of range");
1943 0 : return mCharacterGlyphs[aPos].IsClusterStart();
1944 : }
1945 :
1946 : bool IsLigatureGroupStart(PRUint32 aPos) {
1947 : NS_ASSERTION(aPos < Length(), "aPos out of range");
1948 : return mCharacterGlyphs[aPos].IsLigatureGroupStart();
1949 : }
1950 :
1951 0 : PRUint32 Length() const {
1952 0 : return mLength;
1953 : }
1954 :
1955 0 : const PRUint8* Text8Bit() const {
1956 0 : NS_ASSERTION(TextIs8Bit(), "invalid use of Text8Bit()");
1957 0 : return reinterpret_cast<const PRUint8*>(&mCharacterGlyphs[Length()]);
1958 : }
1959 :
1960 0 : const PRUnichar* TextUnicode() const {
1961 0 : NS_ASSERTION(!TextIs8Bit(), "invalid use of TextUnicode()");
1962 0 : return reinterpret_cast<const PRUnichar*>(&mCharacterGlyphs[Length()]);
1963 : }
1964 :
1965 0 : PRUnichar GetCharAt(PRUint32 aOffset) const {
1966 0 : NS_ASSERTION(aOffset < Length(), "aOffset out of range");
1967 0 : return TextIs8Bit() ?
1968 0 : PRUnichar(Text8Bit()[aOffset]) : TextUnicode()[aOffset];
1969 : }
1970 :
1971 0 : PRUint32 Flags() const {
1972 0 : return mFlags;
1973 : }
1974 :
1975 0 : bool IsRightToLeft() const {
1976 0 : return (Flags() & gfxTextRunFactory::TEXT_IS_RTL) != 0;
1977 : }
1978 :
1979 : float GetDirection() const {
1980 : return IsRightToLeft() ? -1.0 : 1.0;
1981 : }
1982 :
1983 0 : bool DisableLigatures() const {
1984 0 : return (Flags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) != 0;
1985 : }
1986 :
1987 0 : bool TextIs8Bit() const {
1988 0 : return (Flags() & gfxTextRunFactory::TEXT_IS_8BIT) != 0;
1989 : }
1990 :
1991 0 : PRInt32 Script() const {
1992 0 : return mScript;
1993 : }
1994 :
1995 0 : PRInt32 AppUnitsPerDevUnit() const {
1996 0 : return mAppUnitsPerDevUnit;
1997 : }
1998 :
1999 0 : void ResetAge() {
2000 0 : mAgeCounter = 0;
2001 0 : }
2002 0 : PRUint32 IncrementAge() {
2003 0 : return ++mAgeCounter;
2004 : }
2005 :
2006 0 : void SetSimpleGlyph(PRUint32 aCharIndex, CompressedGlyph aGlyph) {
2007 0 : NS_ASSERTION(aGlyph.IsSimpleGlyph(), "Should be a simple glyph here");
2008 0 : NS_ASSERTION(mCharacterGlyphs, "mCharacterGlyphs pointer is null!");
2009 0 : mCharacterGlyphs[aCharIndex] = aGlyph;
2010 0 : }
2011 :
2012 : void SetGlyphs(PRUint32 aCharIndex, CompressedGlyph aGlyph,
2013 : const DetailedGlyph *aGlyphs);
2014 :
2015 : void SetMissingGlyph(PRUint32 aIndex, PRUint32 aChar, gfxFont *aFont);
2016 :
2017 0 : void SetIsSpace(PRUint32 aIndex) {
2018 0 : mCharacterGlyphs[aIndex].SetIsSpace();
2019 0 : }
2020 :
2021 0 : void SetIsLowSurrogate(PRUint32 aIndex) {
2022 0 : SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nsnull);
2023 0 : mCharacterGlyphs[aIndex].SetIsLowSurrogate();
2024 0 : }
2025 :
2026 : bool FilterIfIgnorable(PRUint32 aIndex);
2027 :
2028 0 : const CompressedGlyph *GetCharacterGlyphs() const {
2029 0 : return &mCharacterGlyphs[0];
2030 : }
2031 :
2032 0 : bool HasDetailedGlyphs() const {
2033 0 : return mDetailedGlyphs != nsnull;
2034 : }
2035 :
2036 : // NOTE that this must not be called for a character offset that does
2037 : // not have any DetailedGlyph records; callers must have verified that
2038 : // mCharacterGlyphs[aCharIndex].GetGlyphCount() is greater than zero.
2039 0 : DetailedGlyph *GetDetailedGlyphs(PRUint32 aCharIndex) const {
2040 0 : NS_ASSERTION(HasDetailedGlyphs() &&
2041 : !mCharacterGlyphs[aCharIndex].IsSimpleGlyph() &&
2042 : mCharacterGlyphs[aCharIndex].GetGlyphCount() > 0,
2043 : "invalid use of GetDetailedGlyphs; check the caller!");
2044 0 : return mDetailedGlyphs->Get(aCharIndex);
2045 : }
2046 :
2047 : void AdjustAdvancesForSyntheticBold(float aSynBoldOffset);
2048 :
2049 : // this is a public static method in order to make it available
2050 : // for gfxTextRun to use directly on its own CompressedGlyph array,
2051 : // in addition to the use within ShapedWord
2052 : static void
2053 : SetupClusterBoundaries(CompressedGlyph *aGlyphs,
2054 : const PRUnichar *aString, PRUint32 aLength);
2055 :
2056 : private:
2057 : // so that gfxTextRun can share our DetailedGlyphStore class
2058 : friend class gfxTextRun;
2059 :
2060 : // Construct storage for a ShapedWord, ready to receive glyph data
2061 0 : gfxShapedWord(const PRUint8 *aText, PRUint32 aLength,
2062 : PRInt32 aRunScript, PRInt32 aAppUnitsPerDevUnit,
2063 : PRUint32 aFlags)
2064 : : mLength(aLength)
2065 : , mFlags(aFlags | gfxTextRunFactory::TEXT_IS_8BIT)
2066 : , mAppUnitsPerDevUnit(aAppUnitsPerDevUnit)
2067 : , mScript(aRunScript)
2068 0 : , mAgeCounter(0)
2069 : {
2070 0 : memset(mCharacterGlyphs, 0, aLength * sizeof(CompressedGlyph));
2071 0 : PRUint8 *text = reinterpret_cast<PRUint8*>(&mCharacterGlyphs[aLength]);
2072 0 : memcpy(text, aText, aLength * sizeof(PRUint8));
2073 0 : }
2074 :
2075 0 : gfxShapedWord(const PRUnichar *aText, PRUint32 aLength,
2076 : PRInt32 aRunScript, PRInt32 aAppUnitsPerDevUnit,
2077 : PRUint32 aFlags)
2078 : : mLength(aLength)
2079 : , mFlags(aFlags)
2080 : , mAppUnitsPerDevUnit(aAppUnitsPerDevUnit)
2081 : , mScript(aRunScript)
2082 0 : , mAgeCounter(0)
2083 : {
2084 0 : memset(mCharacterGlyphs, 0, aLength * sizeof(CompressedGlyph));
2085 0 : PRUnichar *text = reinterpret_cast<PRUnichar*>(&mCharacterGlyphs[aLength]);
2086 0 : memcpy(text, aText, aLength * sizeof(PRUnichar));
2087 0 : SetupClusterBoundaries(&mCharacterGlyphs[0], aText, aLength);
2088 0 : }
2089 :
2090 : // Allocate aCount DetailedGlyphs for the given index
2091 : DetailedGlyph *AllocateDetailedGlyphs(PRUint32 aCharIndex,
2092 : PRUint32 aCount);
2093 :
2094 : // For characters whose glyph data does not fit the "simple" glyph criteria
2095 : // in CompressedGlyph, we use a sorted array to store the association
2096 : // between the source character offset and an index into an array
2097 : // DetailedGlyphs. The CompressedGlyph record includes a count of
2098 : // the number of DetailedGlyph records that belong to the character,
2099 : // starting at the given index.
2100 0 : class DetailedGlyphStore {
2101 : public:
2102 0 : DetailedGlyphStore()
2103 0 : : mLastUsed(0)
2104 0 : { }
2105 :
2106 : // This is optimized for the most common calling patterns:
2107 : // we rarely need random access to the records, access is most commonly
2108 : // sequential through the textRun, so we record the last-used index
2109 : // and check whether the caller wants the same record again, or the
2110 : // next; if not, it's most likely we're starting over from the start
2111 : // of the run, so we check the first entry before resorting to binary
2112 : // search as a last resort.
2113 : // NOTE that this must not be called for a character offset that does
2114 : // not have any DetailedGlyph records; callers must have verified that
2115 : // mCharacterGlyphs[aOffset].GetGlyphCount() is greater than zero
2116 : // before calling this, otherwise the assertions here will fire (in a
2117 : // debug build), and we'll probably crash.
2118 0 : DetailedGlyph* Get(PRUint32 aOffset) {
2119 0 : NS_ASSERTION(mOffsetToIndex.Length() > 0,
2120 : "no detailed glyph records!");
2121 0 : DetailedGlyph* details = mDetails.Elements();
2122 : // check common cases (fwd iteration, initial entry, etc) first
2123 0 : if (mLastUsed < mOffsetToIndex.Length() - 1 &&
2124 0 : aOffset == mOffsetToIndex[mLastUsed + 1].mOffset) {
2125 0 : ++mLastUsed;
2126 0 : } else if (aOffset == mOffsetToIndex[0].mOffset) {
2127 0 : mLastUsed = 0;
2128 0 : } else if (aOffset == mOffsetToIndex[mLastUsed].mOffset) {
2129 : // do nothing
2130 0 : } else if (mLastUsed > 0 &&
2131 0 : aOffset == mOffsetToIndex[mLastUsed - 1].mOffset) {
2132 0 : --mLastUsed;
2133 : } else {
2134 : mLastUsed =
2135 0 : mOffsetToIndex.BinaryIndexOf(aOffset, CompareToOffset());
2136 : }
2137 0 : NS_ASSERTION(mLastUsed != nsTArray<DGRec>::NoIndex,
2138 : "detailed glyph record missing!");
2139 0 : return details + mOffsetToIndex[mLastUsed].mIndex;
2140 : }
2141 :
2142 0 : DetailedGlyph* Allocate(PRUint32 aOffset, PRUint32 aCount) {
2143 0 : PRUint32 detailIndex = mDetails.Length();
2144 0 : DetailedGlyph *details = mDetails.AppendElements(aCount);
2145 0 : if (!details) {
2146 0 : return nsnull;
2147 : }
2148 : // We normally set up glyph records sequentially, so the common case
2149 : // here is to append new records to the mOffsetToIndex array;
2150 : // test for that before falling back to the InsertElementSorted
2151 : // method.
2152 0 : if (mOffsetToIndex.Length() == 0 ||
2153 0 : aOffset > mOffsetToIndex[mOffsetToIndex.Length() - 1].mOffset) {
2154 0 : if (!mOffsetToIndex.AppendElement(DGRec(aOffset, detailIndex))) {
2155 0 : return nsnull;
2156 : }
2157 : } else {
2158 0 : if (!mOffsetToIndex.InsertElementSorted(DGRec(aOffset, detailIndex),
2159 0 : CompareRecordOffsets())) {
2160 0 : return nsnull;
2161 : }
2162 : }
2163 0 : return details;
2164 : }
2165 :
2166 0 : size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) {
2167 0 : return aMallocSizeOf(this) +
2168 0 : mDetails.SizeOfExcludingThis(aMallocSizeOf) +
2169 0 : mOffsetToIndex.SizeOfExcludingThis(aMallocSizeOf);
2170 : }
2171 :
2172 : private:
2173 0 : struct DGRec {
2174 0 : DGRec(const PRUint32& aOffset, const PRUint32& aIndex)
2175 0 : : mOffset(aOffset), mIndex(aIndex) { }
2176 : PRUint32 mOffset; // source character offset in the textrun
2177 : PRUint32 mIndex; // index where this char's DetailedGlyphs begin
2178 : };
2179 :
2180 : struct CompareToOffset {
2181 0 : bool Equals(const DGRec& a, const PRUint32& b) const {
2182 0 : return a.mOffset == b;
2183 : }
2184 0 : bool LessThan(const DGRec& a, const PRUint32& b) const {
2185 0 : return a.mOffset < b;
2186 : }
2187 : };
2188 :
2189 : struct CompareRecordOffsets {
2190 0 : bool Equals(const DGRec& a, const DGRec& b) const {
2191 0 : return a.mOffset == b.mOffset;
2192 : }
2193 0 : bool LessThan(const DGRec& a, const DGRec& b) const {
2194 0 : return a.mOffset < b.mOffset;
2195 : }
2196 : };
2197 :
2198 : // Concatenated array of all the DetailedGlyph records needed for the
2199 : // textRun; individual character offsets are associated with indexes
2200 : // into this array via the mOffsetToIndex table.
2201 : nsTArray<DetailedGlyph> mDetails;
2202 :
2203 : // For each character offset that needs DetailedGlyphs, we record the
2204 : // index in mDetails where the list of glyphs begins. This array is
2205 : // sorted by mOffset.
2206 : nsTArray<DGRec> mOffsetToIndex;
2207 :
2208 : // Records the most recently used index into mOffsetToIndex, so that
2209 : // we can support sequential access more quickly than just doing
2210 : // a binary search each time.
2211 : nsTArray<DGRec>::index_type mLastUsed;
2212 : };
2213 :
2214 : nsAutoPtr<DetailedGlyphStore> mDetailedGlyphs;
2215 :
2216 : // Number of PRUnichar characters and CompressedGlyph glyph records;
2217 : // note that gfx font code will never attempt to create a ShapedWord
2218 : // with a huge number of characters, so we could limit this to 16 bits
2219 : // to minimize memory usage for large numbers of cached words.
2220 : PRUint32 mLength;
2221 :
2222 : PRUint32 mFlags;
2223 :
2224 : PRInt32 mAppUnitsPerDevUnit;
2225 : PRInt32 mScript;
2226 :
2227 : PRUint32 mAgeCounter;
2228 :
2229 : // The mCharacterGlyphs array is actually a variable-size member;
2230 : // when the ShapedWord is created, its size will be increased as necessary
2231 : // to allow the proper number of glyphs to be stored.
2232 : // The original text, in either 8-bit or 16-bit form, will be stored
2233 : // immediately following the CompressedGlyphs.
2234 : CompressedGlyph mCharacterGlyphs[1];
2235 : };
2236 :
2237 : /**
2238 : * gfxTextRun is an abstraction for drawing and measuring substrings of a run
2239 : * of text. It stores runs of positioned glyph data, each run having a single
2240 : * gfxFont. The glyphs are associated with a string of source text, and the
2241 : * gfxTextRun APIs take parameters that are offsets into that source text.
2242 : *
2243 : * gfxTextRuns are not refcounted. They should be deleted when no longer required.
2244 : *
2245 : * gfxTextRuns are mostly immutable. The only things that can change are
2246 : * inter-cluster spacing and line break placement. Spacing is always obtained
2247 : * lazily by methods that need it, it is not cached. Line breaks are stored
2248 : * persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
2249 : * not actually do anything to explicitly account for line breaks). Initially
2250 : * there are no line breaks. The textrun can record line breaks before or after
2251 : * any given cluster. (Line breaks specified inside clusters are ignored.)
2252 : *
2253 : * It is important that zero-length substrings are handled correctly. This will
2254 : * be on the test!
2255 : */
2256 : class THEBES_API gfxTextRun {
2257 : public:
2258 : // we use the same glyph storage as gfxShapedWord, to facilitate copying
2259 : // glyph data from shaped words into text runs as needed
2260 : typedef gfxShapedWord::CompressedGlyph CompressedGlyph;
2261 : typedef gfxShapedWord::DetailedGlyph DetailedGlyph;
2262 : typedef gfxShapedWord::DetailedGlyphStore DetailedGlyphStore;
2263 :
2264 : // Override operator delete to properly free the object that was
2265 : // allocated via moz_malloc.
2266 0 : void operator delete(void* p) {
2267 0 : moz_free(p);
2268 0 : }
2269 :
2270 : virtual ~gfxTextRun();
2271 :
2272 : typedef gfxFont::RunMetrics Metrics;
2273 :
2274 : // Public textrun API for general use
2275 :
2276 0 : bool IsClusterStart(PRUint32 aPos) {
2277 0 : NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
2278 0 : return mCharacterGlyphs[aPos].IsClusterStart();
2279 : }
2280 : bool IsLigatureGroupStart(PRUint32 aPos) {
2281 : NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
2282 : return mCharacterGlyphs[aPos].IsLigatureGroupStart();
2283 : }
2284 : bool CanBreakLineBefore(PRUint32 aPos) {
2285 : NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
2286 : return mCharacterGlyphs[aPos].CanBreakBefore() ==
2287 : CompressedGlyph::FLAG_BREAK_TYPE_NORMAL;
2288 : }
2289 : bool CanHyphenateBefore(PRUint32 aPos) {
2290 : NS_ASSERTION(aPos < mCharacterCount, "aPos out of range");
2291 : return mCharacterGlyphs[aPos].CanBreakBefore() ==
2292 : CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
2293 : }
2294 :
2295 : bool CharIsSpace(PRUint32 aPos) {
2296 : NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
2297 : return mCharacterGlyphs[aPos].CharIsSpace();
2298 : }
2299 : bool CharIsTab(PRUint32 aPos) {
2300 : NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
2301 : return mCharacterGlyphs[aPos].CharIsTab();
2302 : }
2303 : bool CharIsNewline(PRUint32 aPos) {
2304 : NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
2305 : return mCharacterGlyphs[aPos].CharIsNewline();
2306 : }
2307 : bool CharIsLowSurrogate(PRUint32 aPos) {
2308 : NS_ASSERTION(0 <= aPos && aPos < mCharacterCount, "aPos out of range");
2309 : return mCharacterGlyphs[aPos].CharIsLowSurrogate();
2310 : }
2311 :
2312 0 : PRUint32 GetLength() { return mCharacterCount; }
2313 :
2314 : // All PRUint32 aStart, PRUint32 aLength ranges below are restricted to
2315 : // grapheme cluster boundaries! All offsets are in terms of the string
2316 : // passed into MakeTextRun.
2317 :
2318 : // All coordinates are in layout/app units
2319 :
2320 : /**
2321 : * Set the potential linebreaks for a substring of the textrun. These are
2322 : * the "allow break before" points. Initially, there are no potential
2323 : * linebreaks.
2324 : *
2325 : * This can change glyphs and/or geometry! Some textruns' shapes
2326 : * depend on potential line breaks (e.g., title-case-converting textruns).
2327 : * This function is virtual so that those textruns can reshape themselves.
2328 : *
2329 : * @return true if this changed the linebreaks, false if the new line
2330 : * breaks are the same as the old
2331 : */
2332 : virtual bool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
2333 : PRUint8 *aBreakBefore,
2334 : gfxContext *aRefContext);
2335 :
2336 : /**
2337 : * Layout provides PropertyProvider objects. These allow detection of
2338 : * potential line break points and computation of spacing. We pass the data
2339 : * this way to allow lazy data acquisition; for example BreakAndMeasureText
2340 : * will want to only ask for properties of text it's actually looking at.
2341 : *
2342 : * NOTE that requested spacing may not actually be applied, if the textrun
2343 : * is unable to apply it in some context. Exception: spacing around a
2344 : * whitespace character MUST always be applied.
2345 : */
2346 : class PropertyProvider {
2347 : public:
2348 : // Detect hyphenation break opportunities in the given range; breaks
2349 : // not at cluster boundaries will be ignored.
2350 : virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
2351 : bool *aBreakBefore) = 0;
2352 :
2353 : // Returns the provider's hyphenation setting, so callers can decide
2354 : // whether it is necessary to call GetHyphenationBreaks.
2355 : // Result is an NS_STYLE_HYPHENS_* value.
2356 : virtual PRInt8 GetHyphensOption() = 0;
2357 :
2358 : // Returns the extra width that will be consumed by a hyphen. This should
2359 : // be constant for a given textrun.
2360 : virtual gfxFloat GetHyphenWidth() = 0;
2361 :
2362 : typedef gfxFont::Spacing Spacing;
2363 :
2364 : /**
2365 : * Get the spacing around the indicated characters. Spacing must be zero
2366 : * inside clusters. In other words, if character i is not
2367 : * CLUSTER_START, then character i-1 must have zero after-spacing and
2368 : * character i must have zero before-spacing.
2369 : */
2370 : virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength,
2371 : Spacing *aSpacing) = 0;
2372 : };
2373 :
2374 : class ClusterIterator {
2375 : public:
2376 : ClusterIterator(gfxTextRun *aTextRun);
2377 :
2378 : void Reset();
2379 :
2380 : bool NextCluster();
2381 :
2382 : PRUint32 Position() const {
2383 : return mCurrentChar;
2384 : }
2385 :
2386 : PRUint32 ClusterLength() const;
2387 :
2388 : gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
2389 :
2390 : private:
2391 : gfxTextRun *mTextRun;
2392 : PRUint32 mCurrentChar;
2393 : };
2394 :
2395 : /**
2396 : * Draws a substring. Uses only GetSpacing from aBreakProvider.
2397 : * The provided point is the baseline origin on the left of the string
2398 : * for LTR, on the right of the string for RTL.
2399 : * @param aAdvanceWidth if non-null, the advance width of the substring
2400 : * is returned here.
2401 : *
2402 : * Drawing should respect advance widths in the sense that for LTR runs,
2403 : * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
2404 : * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
2405 : * dirty, &provider, nsnull) should have the same effect as
2406 : * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nsnull).
2407 : * For RTL runs the rule is:
2408 : * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
2409 : * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
2410 : * dirty, &provider, nsnull) should have the same effect as
2411 : * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nsnull).
2412 : *
2413 : * Glyphs should be drawn in logical content order, which can be significant
2414 : * if they overlap (perhaps due to negative spacing).
2415 : */
2416 : void Draw(gfxContext *aContext, gfxPoint aPt,
2417 : gfxFont::DrawMode aDrawMode,
2418 : PRUint32 aStart, PRUint32 aLength,
2419 : PropertyProvider *aProvider,
2420 : gfxFloat *aAdvanceWidth, gfxPattern *aStrokePattern);
2421 :
2422 : /**
2423 : * Computes the ReflowMetrics for a substring.
2424 : * Uses GetSpacing from aBreakProvider.
2425 : * @param aBoundingBoxType which kind of bounding box (loose/tight)
2426 : */
2427 : Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
2428 : gfxFont::BoundingBoxType aBoundingBoxType,
2429 : gfxContext *aRefContextForTightBoundingBox,
2430 : PropertyProvider *aProvider);
2431 :
2432 : /**
2433 : * Computes just the advance width for a substring.
2434 : * Uses GetSpacing from aBreakProvider.
2435 : */
2436 : gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
2437 : PropertyProvider *aProvider);
2438 :
2439 : /**
2440 : * Clear all stored line breaks for the given range (both before and after),
2441 : * and then set the line-break state before aStart to aBreakBefore and
2442 : * after the last cluster to aBreakAfter.
2443 : *
2444 : * We require that before and after line breaks be consistent. For clusters
2445 : * i and i+1, we require that if there is a break after cluster i, a break
2446 : * will be specified before cluster i+1. This may be temporarily violated
2447 : * (e.g. after reflowing line L and before reflowing line L+1); to handle
2448 : * these temporary violations, we say that there is a break betwen i and i+1
2449 : * if a break is specified after i OR a break is specified before i+1.
2450 : *
2451 : * This can change textrun geometry! The existence of a linebreak can affect
2452 : * the advance width of the cluster before the break (when kerning) or the
2453 : * geometry of one cluster before the break or any number of clusters
2454 : * after the break. (The one-cluster-before-the-break limit is somewhat
2455 : * arbitrary; if some scripts require breaking it, then we need to
2456 : * alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
2457 : * it could affect the layout of frames before it...)
2458 : *
2459 : * We return true if glyphs or geometry changed, false otherwise. This
2460 : * function is virtual so that gfxTextRun subclasses can reshape
2461 : * properly.
2462 : *
2463 : * @param aAdvanceWidthDelta if non-null, returns the change in advance
2464 : * width of the given range.
2465 : */
2466 : virtual bool SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
2467 : bool aLineBreakBefore, bool aLineBreakAfter,
2468 : gfxFloat *aAdvanceWidthDelta,
2469 : gfxContext *aRefContext);
2470 :
2471 : /**
2472 : * Finds the longest substring that will fit into the given width.
2473 : * Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
2474 : * Guarantees the following:
2475 : * -- 0 <= result <= aMaxLength
2476 : * -- result is the maximal value of N such that either
2477 : * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
2478 : * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
2479 : * OR N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth
2480 : * where GetAdvanceWidth assumes the effect of
2481 : * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
2482 : * -- if no such N exists, then result is the smallest N such that
2483 : * N < aMaxLength && line break at N
2484 : * OR N < aMaxLength && hyphen break at N
2485 : * OR N == aMaxLength
2486 : *
2487 : * The call has the effect of
2488 : * SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider)
2489 : * and the returned metrics and the invariants above reflect this.
2490 : *
2491 : * @param aMaxLength this can be PR_UINT32_MAX, in which case the length used
2492 : * is up to the end of the string
2493 : * @param aLineBreakBefore set to true if and only if there is an actual
2494 : * line break at the start of this string.
2495 : * @param aSuppressInitialBreak if true, then we assume there is no possible
2496 : * linebreak before aStart. If false, then we will check the internal
2497 : * line break opportunity state before deciding whether to return 0 as the
2498 : * character to break before.
2499 : * @param aTrimWhitespace if non-null, then we allow a trailing run of
2500 : * spaces to be trimmed; the width of the space(s) will not be included in
2501 : * the measured string width for comparison with the limit aWidth, and
2502 : * trimmed spaces will not be included in returned metrics. The width
2503 : * of the trimmed spaces will be returned in aTrimWhitespace.
2504 : * Trimmed spaces are still counted in the "characters fit" result.
2505 : * @param aMetrics if non-null, we fill this in for the returned substring.
2506 : * If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
2507 : * @param aBoundingBoxType whether to make the bounding box in aMetrics tight
2508 : * @param aRefContextForTightBoundingBox a reference context to get the
2509 : * tight bounding box, if requested
2510 : * @param aUsedHyphenation if non-null, records if we selected a hyphenation break
2511 : * @param aLastBreak if non-null and result is aMaxLength, we set this to
2512 : * the maximal N such that
2513 : * N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
2514 : * OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
2515 : * or PR_UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
2516 : * the effect of
2517 : * SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
2518 : *
2519 : * @param aCanWordWrap true if we can break between any two grapheme
2520 : * clusters. This is set by word-wrap: break-word
2521 : *
2522 : * @param aBreakPriority in/out the priority of the break opportunity
2523 : * saved in the line. If we are prioritizing break opportunities, we will
2524 : * not set a break with a lower priority. @see gfxBreakPriority.
2525 : *
2526 : * Note that negative advance widths are possible especially if negative
2527 : * spacing is provided.
2528 : */
2529 : PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
2530 : bool aLineBreakBefore, gfxFloat aWidth,
2531 : PropertyProvider *aProvider,
2532 : bool aSuppressInitialBreak,
2533 : gfxFloat *aTrimWhitespace,
2534 : Metrics *aMetrics,
2535 : gfxFont::BoundingBoxType aBoundingBoxType,
2536 : gfxContext *aRefContextForTightBoundingBox,
2537 : bool *aUsedHyphenation,
2538 : PRUint32 *aLastBreak,
2539 : bool aCanWordWrap,
2540 : gfxBreakPriority *aBreakPriority);
2541 :
2542 : /**
2543 : * Update the reference context.
2544 : * XXX this is a hack. New text frame does not call this. Use only
2545 : * temporarily for old text frame.
2546 : */
2547 : void SetContext(gfxContext *aContext) {}
2548 :
2549 : // Utility getters
2550 :
2551 0 : bool IsRightToLeft() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0; }
2552 0 : gfxFloat GetDirection() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) ? -1.0 : 1.0; }
2553 : void *GetUserData() const { return mUserData; }
2554 : void SetUserData(void *aUserData) { mUserData = aUserData; }
2555 0 : PRUint32 GetFlags() const { return mFlags; }
2556 : void SetFlagBits(PRUint32 aFlags) {
2557 : NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
2558 : "Only user flags should be mutable");
2559 : mFlags |= aFlags;
2560 : }
2561 : void ClearFlagBits(PRUint32 aFlags) {
2562 : NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
2563 : "Only user flags should be mutable");
2564 : mFlags &= ~aFlags;
2565 : }
2566 : const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
2567 0 : PRUint32 GetAppUnitsPerDevUnit() const { return mAppUnitsPerDevUnit; }
2568 : gfxFontGroup *GetFontGroup() const { return mFontGroup; }
2569 :
2570 :
2571 : // Call this, don't call "new gfxTextRun" directly. This does custom
2572 : // allocation and initialization
2573 : static gfxTextRun *Create(const gfxTextRunFactory::Parameters *aParams,
2574 : const void *aText, PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags);
2575 :
2576 : // The text is divided into GlyphRuns as necessary
2577 0 : struct GlyphRun {
2578 : nsRefPtr<gfxFont> mFont; // never null
2579 : PRUint32 mCharacterOffset; // into original UTF16 string
2580 : PRUint8 mMatchType;
2581 : };
2582 :
2583 : class THEBES_API GlyphRunIterator {
2584 : public:
2585 0 : GlyphRunIterator(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aLength)
2586 0 : : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
2587 0 : mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
2588 0 : }
2589 : bool NextRun();
2590 0 : GlyphRun *GetGlyphRun() { return mGlyphRun; }
2591 0 : PRUint32 GetStringStart() { return mStringStart; }
2592 0 : PRUint32 GetStringEnd() { return mStringEnd; }
2593 : private:
2594 : gfxTextRun *mTextRun;
2595 : GlyphRun *mGlyphRun;
2596 : PRUint32 mStringStart;
2597 : PRUint32 mStringEnd;
2598 : PRUint32 mNextIndex;
2599 : PRUint32 mStartOffset;
2600 : PRUint32 mEndOffset;
2601 : };
2602 :
2603 : class GlyphRunOffsetComparator {
2604 : public:
2605 0 : bool Equals(const GlyphRun& a,
2606 : const GlyphRun& b) const
2607 : {
2608 0 : return a.mCharacterOffset == b.mCharacterOffset;
2609 : }
2610 :
2611 0 : bool LessThan(const GlyphRun& a,
2612 : const GlyphRun& b) const
2613 : {
2614 0 : return a.mCharacterOffset < b.mCharacterOffset;
2615 : }
2616 : };
2617 :
2618 : friend class GlyphRunIterator;
2619 : friend class FontSelector;
2620 :
2621 : // API for setting up the textrun glyphs. Should only be called by
2622 : // things that construct textruns.
2623 : /**
2624 : * We've found a run of text that should use a particular font. Call this
2625 : * only during initialization when font substitution has been computed.
2626 : * Call it before setting up the glyphs for the characters in this run;
2627 : * SetMissingGlyph requires that the correct glyphrun be installed.
2628 : *
2629 : * If aForceNewRun, a new glyph run will be added, even if the
2630 : * previously added run uses the same font. If glyph runs are
2631 : * added out of strictly increasing aStartCharIndex order (via
2632 : * force), then SortGlyphRuns must be called after all glyph runs
2633 : * are added before any further operations are performed with this
2634 : * TextRun.
2635 : */
2636 : nsresult AddGlyphRun(gfxFont *aFont, PRUint8 aMatchType,
2637 : PRUint32 aStartCharIndex, bool aForceNewRun);
2638 : void ResetGlyphRuns() { mGlyphRuns.Clear(); }
2639 : void SortGlyphRuns();
2640 : void SanitizeGlyphRuns();
2641 :
2642 : // Call the following glyph-setters during initialization or during reshaping
2643 : // only. It is OK to overwrite existing data for a character.
2644 0 : void SetSimpleGlyph(PRUint32 aCharIndex, CompressedGlyph aGlyph) {
2645 0 : NS_ASSERTION(aGlyph.IsSimpleGlyph(), "Should be a simple glyph here");
2646 0 : mCharacterGlyphs[aCharIndex] = aGlyph;
2647 0 : }
2648 : /**
2649 : * Set the glyph data for a character. aGlyphs may be null if aGlyph is a
2650 : * simple glyph or has no associated glyphs. If non-null the data is copied,
2651 : * the caller retains ownership.
2652 : */
2653 : void SetGlyphs(PRUint32 aCharIndex, CompressedGlyph aGlyph,
2654 : const DetailedGlyph *aGlyphs);
2655 : void SetMissingGlyph(PRUint32 aCharIndex, PRUint32 aUnicodeChar);
2656 : void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, PRUint32 aCharIndex);
2657 :
2658 : // Set the glyph data for the given character index to the font's
2659 : // space glyph, IF this can be done as a "simple" glyph record
2660 : // (not requiring a DetailedGlyph entry). This avoids the need to call
2661 : // the font shaper and go through the shaped-word cache for most spaces.
2662 : //
2663 : // The parameter aSpaceChar is the original character code for which
2664 : // this space glyph is being used; if this is U+0020, we need to record
2665 : // that it could be trimmed at a run edge, whereas other kinds of space
2666 : // (currently just U+00A0) would not be trimmable/breakable.
2667 : //
2668 : // Returns true if it was able to set simple glyph data for the space;
2669 : // if it returns false, the caller needs to fall back to some other
2670 : // means to create the necessary (detailed) glyph data.
2671 : bool SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext,
2672 : PRUint32 aCharIndex, PRUnichar aSpaceChar);
2673 :
2674 : // Record the positions of specific characters that layout may need to
2675 : // detect in the textrun, even though it doesn't have an explicit copy
2676 : // of the original text. These are recorded using flag bits in the
2677 : // CompressedGlyph record; if necessary, we convert "simple" glyph records
2678 : // to "complex" ones as the Tab and Newline flags are not present in
2679 : // simple CompressedGlyph records.
2680 0 : void SetIsTab(PRUint32 aIndex) {
2681 0 : CompressedGlyph *g = &mCharacterGlyphs[aIndex];
2682 0 : if (g->IsSimpleGlyph()) {
2683 0 : DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
2684 0 : details->mGlyphID = g->GetSimpleGlyph();
2685 0 : details->mAdvance = g->GetSimpleAdvance();
2686 0 : details->mXOffset = details->mYOffset = 0;
2687 0 : SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details);
2688 : }
2689 0 : g->SetIsTab();
2690 0 : }
2691 0 : void SetIsNewline(PRUint32 aIndex) {
2692 0 : CompressedGlyph *g = &mCharacterGlyphs[aIndex];
2693 0 : if (g->IsSimpleGlyph()) {
2694 0 : DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
2695 0 : details->mGlyphID = g->GetSimpleGlyph();
2696 0 : details->mAdvance = g->GetSimpleAdvance();
2697 0 : details->mXOffset = details->mYOffset = 0;
2698 0 : SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details);
2699 : }
2700 0 : g->SetIsNewline();
2701 0 : }
2702 0 : void SetIsLowSurrogate(PRUint32 aIndex) {
2703 0 : SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nsnull);
2704 0 : mCharacterGlyphs[aIndex].SetIsLowSurrogate();
2705 0 : }
2706 :
2707 : /**
2708 : * Prefetch all the glyph extents needed to ensure that Measure calls
2709 : * on this textrun not requesting tight boundingBoxes will succeed. Note
2710 : * that some glyph extents might not be fetched due to OOM or other
2711 : * errors.
2712 : */
2713 : void FetchGlyphExtents(gfxContext *aRefContext);
2714 :
2715 : // API for access to the raw glyph data, needed by gfxFont::Draw
2716 : // and gfxFont::GetBoundingBox
2717 0 : CompressedGlyph *GetCharacterGlyphs() { return mCharacterGlyphs; }
2718 :
2719 : // NOTE that this must not be called for a character offset that does
2720 : // not have any DetailedGlyph records; callers must have verified that
2721 : // mCharacterGlyphs[aCharIndex].GetGlyphCount() is greater than zero.
2722 0 : DetailedGlyph *GetDetailedGlyphs(PRUint32 aCharIndex) {
2723 0 : NS_ASSERTION(mDetailedGlyphs != nsnull &&
2724 : !mCharacterGlyphs[aCharIndex].IsSimpleGlyph() &&
2725 : mCharacterGlyphs[aCharIndex].GetGlyphCount() > 0,
2726 : "invalid use of GetDetailedGlyphs; check the caller!");
2727 0 : return mDetailedGlyphs->Get(aCharIndex);
2728 : }
2729 :
2730 0 : bool HasDetailedGlyphs() { return mDetailedGlyphs != nsnull; }
2731 : PRUint32 CountMissingGlyphs();
2732 0 : const GlyphRun *GetGlyphRuns(PRUint32 *aNumGlyphRuns) {
2733 0 : *aNumGlyphRuns = mGlyphRuns.Length();
2734 0 : return mGlyphRuns.Elements();
2735 : }
2736 : // Returns the index of the GlyphRun containing the given offset.
2737 : // Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
2738 : PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
2739 :
2740 : // Copy glyph data from a ShapedWord into this textrun.
2741 : void CopyGlyphDataFrom(const gfxShapedWord *aSource, PRUint32 aStart);
2742 :
2743 : // Copy glyph data for a range of characters from aSource to this
2744 : // textrun.
2745 : void CopyGlyphDataFrom(gfxTextRun *aSource, PRUint32 aStart,
2746 : PRUint32 aLength, PRUint32 aDest);
2747 :
2748 : nsExpirationState *GetExpirationState() { return &mExpirationState; }
2749 :
2750 : struct LigatureData {
2751 : // textrun offsets of the start and end of the containing ligature
2752 : PRUint32 mLigatureStart;
2753 : PRUint32 mLigatureEnd;
2754 : // appunits advance to the start of the ligature part within the ligature;
2755 : // never includes any spacing
2756 : gfxFloat mPartAdvance;
2757 : // appunits width of the ligature part; includes before-spacing
2758 : // when the part is at the start of the ligature, and after-spacing
2759 : // when the part is as the end of the ligature
2760 : gfxFloat mPartWidth;
2761 :
2762 : bool mClipBeforePart;
2763 : bool mClipAfterPart;
2764 : };
2765 :
2766 : // return storage used by this run, for memory reporter;
2767 : // nsTransformedTextRun needs to override this as it holds additional data
2768 : virtual NS_MUST_OVERRIDE size_t
2769 : SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf);
2770 : virtual NS_MUST_OVERRIDE size_t
2771 : SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf);
2772 :
2773 : // Get the size, if it hasn't already been gotten, marking as it goes.
2774 : size_t MaybeSizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) {
2775 : if (mFlags & gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED) {
2776 : return 0;
2777 : }
2778 : mFlags |= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED;
2779 : return SizeOfIncludingThis(aMallocSizeOf);
2780 : }
2781 : void ResetSizeOfAccountingFlags() {
2782 : mFlags &= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED;
2783 : }
2784 :
2785 : #ifdef DEBUG
2786 : void Dump(FILE* aOutput);
2787 : #endif
2788 :
2789 : protected:
2790 : /**
2791 : * Create a textrun, and set its mCharacterGlyphs to point immediately
2792 : * after the base object; this is ONLY used in conjunction with placement
2793 : * new, after allocating a block large enough for the glyph records to
2794 : * follow the base textrun object.
2795 : */
2796 : gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void *aText,
2797 : PRUint32 aLength, gfxFontGroup *aFontGroup, PRUint32 aFlags);
2798 :
2799 : /**
2800 : * Helper for the Create() factory method to allocate the required
2801 : * glyph storage for a textrun object with the basic size aSize,
2802 : * plus room for aLength glyph records.
2803 : */
2804 : static void* AllocateStorageForTextRun(size_t aSize, PRUint32 aLength);
2805 :
2806 : // All our glyph data is in logical order, not visual.
2807 : // Space for mCharacterGlyphs is allocated fused with the textrun object,
2808 : // and then the constructor sets the pointer to the beginning of this
2809 : // storage area. Thus, this pointer must NOT be freed!
2810 : CompressedGlyph *mCharacterGlyphs;
2811 :
2812 : private:
2813 : // **** general helpers ****
2814 :
2815 : // Allocate aCount DetailedGlyphs for the given index
2816 : DetailedGlyph *AllocateDetailedGlyphs(PRUint32 aCharIndex, PRUint32 aCount);
2817 :
2818 : // Get the total advance for a range of glyphs.
2819 : PRInt32 GetAdvanceForGlyphs(PRUint32 aStart, PRUint32 aEnd);
2820 :
2821 : // Spacing for characters outside the range aSpacingStart/aSpacingEnd
2822 : // is assumed to be zero; such characters are not passed to aProvider.
2823 : // This is useful to protect aProvider from being passed character indices
2824 : // it is not currently able to handle.
2825 : bool GetAdjustedSpacingArray(PRUint32 aStart, PRUint32 aEnd,
2826 : PropertyProvider *aProvider,
2827 : PRUint32 aSpacingStart, PRUint32 aSpacingEnd,
2828 : nsTArray<PropertyProvider::Spacing> *aSpacing);
2829 :
2830 : // **** ligature helpers ****
2831 : // (Platforms do the actual ligaturization, but we need to do a bunch of stuff
2832 : // to handle requests that begin or end inside a ligature)
2833 :
2834 : // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
2835 : LigatureData ComputeLigatureData(PRUint32 aPartStart, PRUint32 aPartEnd,
2836 : PropertyProvider *aProvider);
2837 : gfxFloat ComputePartialLigatureWidth(PRUint32 aPartStart, PRUint32 aPartEnd,
2838 : PropertyProvider *aProvider);
2839 : void DrawPartialLigature(gfxFont *aFont, gfxContext *aCtx,
2840 : PRUint32 aStart, PRUint32 aEnd, gfxPoint *aPt,
2841 : PropertyProvider *aProvider);
2842 : // Advance aStart to the start of the nearest ligature; back up aEnd
2843 : // to the nearest ligature end; may result in *aStart == *aEnd
2844 : void ShrinkToLigatureBoundaries(PRUint32 *aStart, PRUint32 *aEnd);
2845 : // result in appunits
2846 : gfxFloat GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd, PropertyProvider *aProvider);
2847 : void AccumulatePartialLigatureMetrics(gfxFont *aFont,
2848 : PRUint32 aStart, PRUint32 aEnd,
2849 : gfxFont::BoundingBoxType aBoundingBoxType,
2850 : gfxContext *aRefContext,
2851 : PropertyProvider *aProvider,
2852 : Metrics *aMetrics);
2853 :
2854 : // **** measurement helper ****
2855 : void AccumulateMetricsForRun(gfxFont *aFont, PRUint32 aStart, PRUint32 aEnd,
2856 : gfxFont::BoundingBoxType aBoundingBoxType,
2857 : gfxContext *aRefContext,
2858 : PropertyProvider *aProvider,
2859 : PRUint32 aSpacingStart, PRUint32 aSpacingEnd,
2860 : Metrics *aMetrics);
2861 :
2862 : // **** drawing helper ****
2863 : void DrawGlyphs(gfxFont *aFont, gfxContext *aContext,
2864 : gfxFont::DrawMode aDrawMode, gfxPoint *aPt,
2865 : gfxPattern *aStrokePattern, PRUint32 aStart, PRUint32 aEnd,
2866 : PropertyProvider *aProvider,
2867 : PRUint32 aSpacingStart, PRUint32 aSpacingEnd);
2868 :
2869 : nsAutoPtr<DetailedGlyphStore> mDetailedGlyphs;
2870 :
2871 : // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
2872 : // for smaller size especially in the super-common one-glyphrun case
2873 : nsAutoTArray<GlyphRun,1> mGlyphRuns;
2874 :
2875 : void *mUserData;
2876 : gfxFontGroup *mFontGroup; // addrefed
2877 : gfxSkipChars mSkipChars;
2878 : nsExpirationState mExpirationState;
2879 : PRUint32 mAppUnitsPerDevUnit;
2880 : PRUint32 mFlags;
2881 : PRUint32 mCharacterCount;
2882 :
2883 : bool mSkipDrawing; // true if the font group we used had a user font
2884 : // download that's in progress, so we should hide text
2885 : // until the download completes (or timeout fires)
2886 : };
2887 :
2888 : class THEBES_API gfxFontGroup : public gfxTextRunFactory {
2889 : public:
2890 : static void Shutdown(); // platform must call this to release the languageAtomService
2891 :
2892 : gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet = nsnull);
2893 :
2894 : virtual ~gfxFontGroup();
2895 :
2896 0 : virtual gfxFont *GetFontAt(PRInt32 i) {
2897 : // If it turns out to be hard for all clients that cache font
2898 : // groups to call UpdateFontList at appropriate times, we could
2899 : // instead consider just calling UpdateFontList from someplace
2900 : // more central (such as here).
2901 0 : NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
2902 : "Whoever was caching this font group should have "
2903 : "called UpdateFontList on it");
2904 0 : NS_ASSERTION(mFonts.Length() > PRUint32(i),
2905 : "Requesting a font index that doesn't exist");
2906 :
2907 0 : return static_cast<gfxFont*>(mFonts[i]);
2908 : }
2909 0 : virtual PRUint32 FontListLength() const {
2910 0 : return mFonts.Length();
2911 : }
2912 :
2913 : bool Equals(const gfxFontGroup& other) const {
2914 : return mFamilies.Equals(other.mFamilies) &&
2915 : mStyle.Equals(other.mStyle);
2916 : }
2917 :
2918 0 : const gfxFontStyle *GetStyle() const { return &mStyle; }
2919 :
2920 : virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
2921 :
2922 : /**
2923 : * The listed characters should be treated as invisible and zero-width
2924 : * when creating textruns.
2925 : */
2926 : static bool IsInvalidChar(PRUint8 ch);
2927 : static bool IsInvalidChar(PRUnichar ch);
2928 :
2929 : /**
2930 : * Make a textrun for a given string.
2931 : * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
2932 : * textrun will copy it.
2933 : * This calls FetchGlyphExtents on the textrun.
2934 : */
2935 : virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
2936 : const Parameters *aParams, PRUint32 aFlags);
2937 : /**
2938 : * Make a textrun for a given string.
2939 : * If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
2940 : * textrun will copy it.
2941 : * This calls FetchGlyphExtents on the textrun.
2942 : */
2943 : virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
2944 : const Parameters *aParams, PRUint32 aFlags);
2945 :
2946 : /**
2947 : * Textrun creation helper for clients that don't want to pass
2948 : * a full Parameters record.
2949 : */
2950 : template<typename T>
2951 : gfxTextRun *MakeTextRun(const T *aString, PRUint32 aLength,
2952 : gfxContext *aRefContext,
2953 : PRUint32 aAppUnitsPerDevUnit,
2954 : PRUint32 aFlags)
2955 : {
2956 : gfxTextRunFactory::Parameters params = {
2957 : aRefContext, nsnull, nsnull, nsnull, 0, aAppUnitsPerDevUnit
2958 : };
2959 : return MakeTextRun(aString, aLength, ¶ms, aFlags);
2960 : }
2961 :
2962 : /* helper function for splitting font families on commas and
2963 : * calling a function for each family to fill the mFonts array
2964 : */
2965 : typedef bool (*FontCreationCallback) (const nsAString& aName,
2966 : const nsACString& aGenericName,
2967 : bool aUseFontSet,
2968 : void *closure);
2969 : bool ForEachFont(const nsAString& aFamilies,
2970 : nsIAtom *aLanguage,
2971 : FontCreationCallback fc,
2972 : void *closure);
2973 : bool ForEachFont(FontCreationCallback fc, void *closure);
2974 :
2975 : /**
2976 : * Check whether a given font (specified by its gfxFontEntry)
2977 : * is already in the fontgroup's list of actual fonts
2978 : */
2979 : bool HasFont(const gfxFontEntry *aFontEntry);
2980 :
2981 : const nsString& GetFamilies() { return mFamilies; }
2982 :
2983 : // This returns the preferred underline for this font group.
2984 : // Some CJK fonts have wrong underline offset in its metrics.
2985 : // If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset.
2986 : // The value should be lower value of first font's metrics and the bad font's metrics.
2987 : // Otherwise, this returns from first font's metrics.
2988 : enum { UNDERLINE_OFFSET_NOT_SET = PR_INT16_MAX };
2989 0 : virtual gfxFloat GetUnderlineOffset() {
2990 0 : if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET)
2991 0 : mUnderlineOffset = GetFontAt(0)->GetMetrics().underlineOffset;
2992 0 : return mUnderlineOffset;
2993 : }
2994 :
2995 : virtual already_AddRefed<gfxFont>
2996 : FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRInt32 aRunScript,
2997 : gfxFont *aPrevMatchedFont,
2998 : PRUint8 *aMatchType);
2999 :
3000 : // search through pref fonts for a character, return nsnull if no matching pref font
3001 : virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
3002 :
3003 : virtual already_AddRefed<gfxFont>
3004 : WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript);
3005 :
3006 : template<typename T>
3007 : void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
3008 : const T *aString, PRUint32 aLength,
3009 : PRInt32 aRunScript);
3010 :
3011 : gfxUserFontSet* GetUserFontSet();
3012 :
3013 : // With downloadable fonts, the composition of the font group can change as fonts are downloaded
3014 : // for each change in state of the user font set, the generation value is bumped to avoid picking up
3015 : // previously created text runs in the text run word cache. For font groups based on stylesheets
3016 : // with no @font-face rule, this always returns 0.
3017 : PRUint64 GetGeneration();
3018 :
3019 : // If there is a user font set, check to see whether the font list or any
3020 : // caches need updating.
3021 : virtual void UpdateFontList();
3022 :
3023 0 : bool ShouldSkipDrawing() const {
3024 0 : return mSkipDrawing;
3025 : }
3026 :
3027 : protected:
3028 : nsString mFamilies;
3029 : gfxFontStyle mStyle;
3030 : nsTArray< nsRefPtr<gfxFont> > mFonts;
3031 : gfxFloat mUnderlineOffset;
3032 :
3033 : gfxUserFontSet* mUserFontSet;
3034 : PRUint64 mCurrGeneration; // track the current user font set generation, rebuild font list if needed
3035 :
3036 : // cache the most recent pref font to avoid general pref font lookup
3037 : nsRefPtr<gfxFontFamily> mLastPrefFamily;
3038 : nsRefPtr<gfxFont> mLastPrefFont;
3039 : eFontPrefLang mLastPrefLang; // lang group for last pref font
3040 : eFontPrefLang mPageLang;
3041 : bool mLastPrefFirstFont; // is this the first font in the list of pref fonts for this lang group?
3042 :
3043 : bool mSkipDrawing; // hide text while waiting for a font
3044 : // download to complete (or fallback
3045 : // timer to fire)
3046 :
3047 : /**
3048 : * Textrun creation short-cuts for special cases where we don't need to
3049 : * call a font shaper to generate glyphs.
3050 : */
3051 : gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, PRUint32 aFlags);
3052 : gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, PRUint32 aFlags);
3053 : gfxTextRun *MakeBlankTextRun(const void* aText, PRUint32 aLength,
3054 : const Parameters *aParams, PRUint32 aFlags);
3055 :
3056 : // Used for construction/destruction. Not intended to change the font set
3057 : // as invalidation of font lists and caches is not considered.
3058 : void SetUserFontSet(gfxUserFontSet *aUserFontSet);
3059 :
3060 : // Initialize the list of fonts
3061 : void BuildFontList();
3062 :
3063 : // Init this font group's font metrics. If there no bad fonts, you don't need to call this.
3064 : // But if there are one or more bad fonts which have bad underline offset,
3065 : // you should call this with the *first* bad font.
3066 : void InitMetricsForBadFont(gfxFont* aBadFont);
3067 :
3068 : // Set up the textrun glyphs for an entire text run:
3069 : // find script runs, and then call InitScriptRun for each
3070 : template<typename T>
3071 0 : void InitTextRun(gfxContext *aContext,
3072 : gfxTextRun *aTextRun,
3073 : const T *aString,
3074 : PRUint32 aLength);
3075 :
3076 : // InitTextRun helper to handle a single script run, by finding font ranges
3077 : // and calling each font's InitTextRun() as appropriate
3078 : template<typename T>
3079 0 : void InitScriptRun(gfxContext *aContext,
3080 : gfxTextRun *aTextRun,
3081 : const T *aString,
3082 : PRUint32 aScriptRunStart,
3083 : PRUint32 aScriptRunEnd,
3084 : PRInt32 aRunScript);
3085 :
3086 : /* If aResolveGeneric is true, then CSS/Gecko generic family names are
3087 : * replaced with preferred fonts.
3088 : *
3089 : * If aResolveFontName is true then fc() is called only for existing fonts
3090 : * and with actual font names. If false then fc() is called with each
3091 : * family name in aFamilies (after resolving CSS/Gecko generic family names
3092 : * if aResolveGeneric).
3093 : * If aUseFontSet is true, the fontgroup's user font set is checked;
3094 : * if false then it is skipped.
3095 : */
3096 : bool ForEachFontInternal(const nsAString& aFamilies,
3097 : nsIAtom *aLanguage,
3098 : bool aResolveGeneric,
3099 : bool aResolveFontName,
3100 : bool aUseFontSet,
3101 : FontCreationCallback fc,
3102 : void *closure);
3103 :
3104 : static bool FontResolverProc(const nsAString& aName, void *aClosure);
3105 :
3106 : static bool FindPlatformFont(const nsAString& aName,
3107 : const nsACString& aGenericName,
3108 : bool aUseFontSet,
3109 : void *closure);
3110 :
3111 : static NS_HIDDEN_(nsILanguageAtomService*) gLangService;
3112 : };
3113 : #endif
|