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
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/
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
15 * The Original Code is Mozilla Foundation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
22 * Vladimir Vukicevic <vladimir@mozilla.com>
23 * Masayuki Nakano <masayuki@d-toybox.com>
24 * Behdad Esfahbod <behdad@gnome.org>
25 * Mats Palmgren <mats.palmgren@bredband.net>
26 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
28 * based on nsFontMetricsPango.cpp by
29 * Christopher Blizzard <blizzard@mozilla.org>
31 * Alternatively, the contents of this file may be used under the terms of
32 * either the GNU General Public License Version 2 or later (the "GPL"), or
33 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
43 * ***** END LICENSE BLOCK ***** */
45 #define PANGO_ENABLE_BACKEND
51 #include "nsUnicodeRange.h"
54 #include "nsIPrefBranch.h"
55 #include "nsIPrefService.h"
56 #include "nsServiceManagerUtils.h"
57 #include "nsMathUtils.h"
59 #include "nsVoidArray.h"
60 #include "nsPromiseFlatString.h"
62 #include "gfxContext.h"
63 #include "gfxPlatformGtk.h"
64 #include "gfxPangoFonts.h"
69 #include <freetype/tttables.h>
74 #include <pango/pango.h>
75 #include <pango/pangocairo.h>
76 #include <pango/pangofc-fontmap.h>
78 #include <gdk/gdkpango.h>
82 #define FLOAT_PANGO_SCALE ((gfxFloat)PANGO_SCALE)
84 #ifndef PANGO_VERSION_CHECK
85 #define PANGO_VERSION_CHECK(x,y,z) 0
87 #ifndef PANGO_GLYPH_UNKNOWN_FLAG
88 #define PANGO_GLYPH_UNKNOWN_FLAG ((PangoGlyph)0x10000000)
90 #ifndef PANGO_GLYPH_EMPTY
91 #define PANGO_GLYPH_EMPTY ((PangoGlyph)0)
93 // For g a PangoGlyph,
94 #define IS_MISSING_GLYPH(g) ((g) & PANGO_GLYPH_UNKNOWN_FLAG)
95 #define IS_EMPTY_GLYPH(g) ((g) == PANGO_GLYPH_EMPTY)
97 static PangoLanguage
*GetPangoLanguage(const nsACString
& aLangGroup
);
99 /* static */ gfxPangoFontCache
* gfxPangoFontCache::sPangoFontCache
= nsnull
;
102 * gfxPangoFontset: An implementation of a PangoFontset for gfxPangoFontMap
105 #define GFX_TYPE_PANGO_FONTSET (gfx_pango_fontset_get_type())
106 #define GFX_PANGO_FONTSET(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FONTSET, gfxPangoFontset))
107 #define GFX_IS_PANGO_FONTSET(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FONTSET))
110 GType
gfx_pango_fontset_get_type (void);
112 #define GFX_PANGO_FONTSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FONTSET, gfxPangoFontsetClass))
113 #define GFX_IS_PANGO_FONTSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FONTSET))
114 #define GFX_PANGO_FONTSET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FONTSET, gfxPangoFontsetClass))
116 // This struct is POD so that it can be used as a GObject.
117 struct gfxPangoFontset
{
118 PangoFontset parent_instance
;
120 PangoContext
*mContext
;
121 PangoFontDescription
*mFontDesc
;
122 PangoLanguage
*mLanguage
;
123 PangoFont
*mBaseFont
;
124 PangoFontMap
*mFontMap
;
125 PangoFontset
*mChildFontset
;
127 static PangoFontset
*
128 NewFontset(PangoContext
*aContext
,
129 const PangoFontDescription
*aFontDesc
,
130 PangoLanguage
*aLanguage
,
131 PangoFont
*aBaseFont
, PangoFontMap
*aFontMap
)
133 gfxPangoFontset
*fontset
= static_cast<gfxPangoFontset
*>
134 (g_object_new(GFX_TYPE_PANGO_FONTSET
, NULL
));
136 fontset
->mContext
= aContext
;
137 g_object_ref(aContext
);
139 fontset
->mFontDesc
= pango_font_description_copy(aFontDesc
);
140 fontset
->mLanguage
= aLanguage
;
142 fontset
->mBaseFont
= aBaseFont
;
144 g_object_ref(aBaseFont
);
146 fontset
->mFontMap
= aFontMap
;
147 g_object_ref(aFontMap
);
149 return PANGO_FONTSET(fontset
);
153 struct gfxPangoFontsetClass
{
154 PangoFontsetClass parent_class
;
157 G_DEFINE_TYPE (gfxPangoFontset
, gfx_pango_fontset
, PANGO_TYPE_FONTSET
)
160 gfx_pango_fontset_init(gfxPangoFontset
*fontset
)
162 fontset
->mContext
= NULL
;
163 fontset
->mFontDesc
= NULL
;
164 fontset
->mLanguage
= NULL
;
165 fontset
->mBaseFont
= NULL
;
166 fontset
->mFontMap
= NULL
;
167 fontset
->mChildFontset
= NULL
;
172 gfx_pango_fontset_finalize(GObject
*object
)
174 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(object
);
177 g_object_unref(self
->mContext
);
179 pango_font_description_free(self
->mFontDesc
);
181 g_object_unref(self
->mBaseFont
);
183 g_object_unref(self
->mFontMap
);
184 if (self
->mChildFontset
)
185 g_object_unref(self
->mChildFontset
);
187 G_OBJECT_CLASS(gfx_pango_fontset_parent_class
)->finalize(object
);
190 static PangoLanguage
*
191 gfx_pango_fontset_get_language(PangoFontset
*fontset
)
193 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(fontset
);
194 return self
->mLanguage
;
197 struct ForeachExceptBaseData
{
198 PangoFont
*mBaseFont
;
199 PangoFontset
*mFontset
;
200 PangoFontsetForeachFunc mFunc
;
205 foreach_except_base_cb(PangoFontset
*fontset
, PangoFont
*font
, gpointer data
)
207 ForeachExceptBaseData
*baseData
=
208 static_cast<ForeachExceptBaseData
*>(data
);
210 // returning false means continue with the other fonts in the set
211 return font
!= baseData
->mBaseFont
&&
212 (*baseData
->mFunc
)(baseData
->mFontset
, font
, baseData
->mData
);
215 static PangoFontset
*
216 EnsureChildFontset(gfxPangoFontset
*self
)
218 if (!self
->mChildFontset
) {
221 // * If this is happening often (e.g. Chinese/Japanese pagess where a
222 // Latin font is specified first), and Pango's 64-entry pattern
223 // cache is not large enough, then a fontset cache here could be
224 // helpful. Ideally we'd only cache the fonts that are actually
225 // accessed rather than all the fonts from the FcFontSort.
227 // * Mozilla's langGroup font prefs could be used to specify preferred
228 // fallback fonts for the script of the characters (as indicated by
229 // Pango in mLanguage), by doing the conversion from gfxFontGroup
230 // "families" to PangoFcFontMap "family" here.
231 self
->mChildFontset
=
232 pango_font_map_load_fontset(self
->mFontMap
, self
->mContext
,
233 self
->mFontDesc
, self
->mLanguage
);
235 return self
->mChildFontset
;
239 gfx_pango_fontset_foreach(PangoFontset
*fontset
, PangoFontsetForeachFunc func
,
242 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(fontset
);
244 if (self
->mBaseFont
&& (*func
)(fontset
, self
->mBaseFont
, data
))
247 // Falling back to secondary fonts
248 PangoFontset
*childFontset
= EnsureChildFontset(self
);
249 ForeachExceptBaseData baseData
= { self
->mBaseFont
, fontset
, func
, data
};
250 pango_fontset_foreach(childFontset
, foreach_except_base_cb
, &baseData
);
254 gfx_pango_fontset_get_font(PangoFontset
*fontset
, guint wc
)
256 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(fontset
);
258 PangoCoverageLevel baseLevel
= PANGO_COVERAGE_NONE
;
259 if (self
->mBaseFont
) {
260 // PangoFcFontMap caches this:
261 PangoCoverage
*coverage
=
262 pango_font_get_coverage(self
->mBaseFont
, self
->mLanguage
);
264 baseLevel
= pango_coverage_get(coverage
, wc
);
265 pango_coverage_unref(coverage
);
269 if (baseLevel
!= PANGO_COVERAGE_EXACT
) {
270 PangoFontset
*childFontset
= EnsureChildFontset(self
);
271 PangoFont
*childFont
= pango_fontset_get_font(childFontset
, wc
);
272 if (!self
->mBaseFont
|| childFont
== self
->mBaseFont
)
276 PangoCoverage
*coverage
=
277 pango_font_get_coverage(childFont
, self
->mLanguage
);
279 PangoCoverageLevel childLevel
=
280 pango_coverage_get(coverage
, wc
);
281 pango_coverage_unref(coverage
);
283 // Only use the child font if better than the base font.
284 if (childLevel
> baseLevel
)
287 g_object_unref(childFont
);
291 g_object_ref(self
->mBaseFont
);
292 return self
->mBaseFont
;
296 gfx_pango_fontset_class_init (gfxPangoFontsetClass
*klass
)
298 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
299 PangoFontsetClass
*fontset_class
= PANGO_FONTSET_CLASS (klass
);
301 object_class
->finalize
= gfx_pango_fontset_finalize
;
302 fontset_class
->get_font
= gfx_pango_fontset_get_font
;
303 // inherit fontset_class->get_metrics (which won't be used anyway)
304 fontset_class
->get_language
= gfx_pango_fontset_get_language
;
305 fontset_class
->foreach
= gfx_pango_fontset_foreach
;
309 * gfxPangoFontMap: An implementation of a PangoFontMap.
311 * This allows the primary (base) font to be specified. There are two
312 * advantages to this:
314 * 1. Always using the same base font irrespective of the language that Pango
315 * chooses for the script means that PANGO_SCRIPT_COMMON characters are
316 * consistently rendered with the same font. (Bug 339513 and bug 416725)
318 * 2. We normally have the base font from the gfxFont cache so this saves a
319 * FcFontSort when the entry has expired from Pango's much smaller pattern
322 * This object references a child font map rather than deriving so that
323 * the cache of the child font map is shared.
326 #define GFX_TYPE_PANGO_FONT_MAP (gfx_pango_font_map_get_type())
327 #define GFX_PANGO_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMap))
328 #define GFX_IS_PANGO_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FONT_MAP))
330 GType
gfx_pango_font_map_get_type (void);
332 #define GFX_PANGO_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
333 #define GFX_IS_PANGO_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FONT_MAP))
334 #define GFX_PANGO_FONT_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
336 // Do not instantiate this class directly, but use NewFontMap.
337 // This struct is POD so that it can be used as a GObject.
338 struct gfxPangoFontMap
{
339 PangoFontMap parent_instance
;
341 PangoFontMap
*mChildFontMap
;
342 PangoFont
*mBaseFont
;
344 static PangoFontMap
*
345 NewFontMap(PangoFontMap
*aChildFontMap
, PangoFont
*aBaseFont
)
347 NS_ASSERTION(strcmp(pango_font_map_get_shape_engine_type(aChildFontMap
),
348 PANGO_RENDER_TYPE_FC
) == 0,
349 "Unexpected child PangoFontMap shape engine type");
351 gfxPangoFontMap
*fontmap
= static_cast<gfxPangoFontMap
*>
352 (g_object_new(GFX_TYPE_PANGO_FONT_MAP
, NULL
));
354 fontmap
->mChildFontMap
= aChildFontMap
;
355 g_object_ref(aChildFontMap
);
357 fontmap
->mBaseFont
= aBaseFont
;
359 g_object_ref(aBaseFont
);
361 return PANGO_FONT_MAP(fontmap
);
365 SetBaseFont(PangoFont
*aBaseFont
)
368 g_object_unref(mBaseFont
);
370 mBaseFont
= aBaseFont
;
373 g_object_ref(aBaseFont
);
377 struct gfxPangoFontMapClass
{
378 PangoFontMapClass parent_class
;
381 G_DEFINE_TYPE (gfxPangoFontMap
, gfx_pango_font_map
, PANGO_TYPE_FONT_MAP
)
384 gfx_pango_font_map_init(gfxPangoFontMap
*fontset
)
386 fontset
->mChildFontMap
= NULL
;
387 fontset
->mBaseFont
= NULL
;
391 gfx_pango_font_map_finalize(GObject
*object
)
393 gfxPangoFontMap
*self
= GFX_PANGO_FONT_MAP(object
);
395 if (self
->mChildFontMap
)
396 g_object_unref(self
->mChildFontMap
);
398 g_object_unref(self
->mBaseFont
);
400 G_OBJECT_CLASS(gfx_pango_font_map_parent_class
)->finalize(object
);
404 gfx_pango_font_map_load_font(PangoFontMap
*fontmap
, PangoContext
*context
,
405 const PangoFontDescription
*description
)
407 gfxPangoFontMap
*self
= GFX_PANGO_FONT_MAP(fontmap
);
408 if (self
->mBaseFont
) {
409 g_object_ref(self
->mBaseFont
);
410 return self
->mBaseFont
;
413 return pango_font_map_load_font(self
->mChildFontMap
, context
, description
);
416 static PangoFontset
*
417 gfx_pango_font_map_load_fontset(PangoFontMap
*fontmap
, PangoContext
*context
,
418 const PangoFontDescription
*desc
,
419 PangoLanguage
*language
)
421 gfxPangoFontMap
*self
= GFX_PANGO_FONT_MAP(fontmap
);
422 return gfxPangoFontset::NewFontset(context
, desc
, language
,
423 self
->mBaseFont
, self
->mChildFontMap
);
427 gfx_pango_font_map_list_families(PangoFontMap
*fontmap
,
428 PangoFontFamily
***families
, int *n_families
)
430 gfxPangoFontMap
*self
= GFX_PANGO_FONT_MAP(fontmap
);
431 pango_font_map_list_families(self
->mChildFontMap
, families
, n_families
);
435 gfx_pango_font_map_class_init(gfxPangoFontMapClass
*klass
)
437 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
438 PangoFontMapClass
*fontmap_class
= PANGO_FONT_MAP_CLASS (klass
);
440 object_class
->finalize
= gfx_pango_font_map_finalize
;
441 fontmap_class
->load_font
= gfx_pango_font_map_load_font
;
442 fontmap_class
->load_fontset
= gfx_pango_font_map_load_fontset
;
443 fontmap_class
->list_families
= gfx_pango_font_map_list_families
;
444 fontmap_class
->shape_engine_type
= PANGO_RENDER_TYPE_FC
;
452 FFRECountHyphens (const nsAString
&aFFREName
)
456 while ((hyphen
= aFFREName
.FindChar('-', hyphen
)) >= 0) {
464 gfxPangoFontGroup::FontCallback (const nsAString
& fontName
,
465 const nsACString
& genericName
,
468 nsStringArray
*sa
= static_cast<nsStringArray
*>(closure
);
470 // We ignore prefs that have three hypens since they are X style prefs.
471 if (genericName
.Length() && FFRECountHyphens(fontName
) >= 3)
474 if (sa
->IndexOf(fontName
) < 0) {
475 sa
->AppendString(fontName
);
482 * Look up the font in the gfxFont cache. If we don't find it, create one.
483 * In either case, add a ref, append it to the aFonts array, and return it ---
484 * except for OOM in which case we do nothing and return null.
486 static already_AddRefed
<gfxPangoFont
>
487 GetOrMakeFont(const nsAString
& aName
, const gfxFontStyle
*aStyle
)
489 nsRefPtr
<gfxFont
> font
= gfxFontCache::GetCache()->Lookup(aName
, aStyle
);
491 font
= new gfxPangoFont(aName
, aStyle
);
494 gfxFontCache::GetCache()->AddNew(font
);
498 return static_cast<gfxPangoFont
*>(f
);
501 gfxPangoFontGroup::gfxPangoFontGroup (const nsAString
& families
,
502 const gfxFontStyle
*aStyle
)
503 : gfxFontGroup(families
, aStyle
)
507 nsStringArray familyArray
;
509 // Leave non-existing fonts in the list so that fontconfig can get the
511 ForEachFontInternal(families
, aStyle
->langGroup
, PR_TRUE
, PR_FALSE
,
512 FontCallback
, &familyArray
);
514 // Construct a string suitable for fontconfig
515 nsAutoString fcFamilies
;
516 if (familyArray
.Count()) {
519 fcFamilies
.Append(*familyArray
[i
]);
521 if (i
>= familyArray
.Count())
523 fcFamilies
.Append(NS_LITERAL_STRING(","));
527 // XXX If there are no fonts, we should use dummy family.
528 // Pango will resolve from this.
529 // behdad: yep, looks good.
530 // printf("%s(%s)\n", NS_ConvertUTF16toUTF8(families).get(),
531 // aStyle->langGroup.get());
532 fcFamilies
.Append(NS_LITERAL_STRING("sans-serif"));
535 nsRefPtr
<gfxPangoFont
> font
= GetOrMakeFont(fcFamilies
, &mStyle
);
537 mFonts
.AppendElement(font
);
541 gfxPangoFontGroup::~gfxPangoFontGroup()
546 gfxPangoFontGroup::Copy(const gfxFontStyle
*aStyle
)
548 return new gfxPangoFontGroup(mFamilies
, aStyle
);
555 gfxPangoFont::gfxPangoFont(const nsAString
&aName
,
556 const gfxFontStyle
*aFontStyle
)
557 : gfxFont(aName
, aFontStyle
),
558 mPangoFont(nsnull
), mCairoFont(nsnull
),
559 mHasMetrics(PR_FALSE
), mAdjustedSize(0)
563 // key for locating a gfxPangoFont corresponding to a PangoFont
564 static GQuark
GetFontQuark()
566 // Not using g_quark_from_static_string() because this module may be
567 // unloaded (which would leave a dangling pointer). Using
568 // g_quark_from_string() instead, which creates a small shutdown leak.
569 static GQuark quark
= g_quark_from_string("moz-gfxFont");
573 gfxPangoFont::gfxPangoFont(PangoFont
*aPangoFont
, const nsAString
&aName
,
574 const gfxFontStyle
*aFontStyle
)
575 : gfxFont(aName
, aFontStyle
),
576 mPangoFont(aPangoFont
), mCairoFont(nsnull
),
577 mHasMetrics(PR_FALSE
), mAdjustedSize(aFontStyle
->size
)
579 g_object_ref(mPangoFont
);
580 g_object_set_qdata(G_OBJECT(mPangoFont
), GetFontQuark(), this);
583 gfxPangoFont::~gfxPangoFont()
586 if (g_object_get_qdata(G_OBJECT(mPangoFont
), GetFontQuark()) == this)
587 g_object_set_qdata(G_OBJECT(mPangoFont
), GetFontQuark(), NULL
);
588 g_object_unref(mPangoFont
);
592 cairo_scaled_font_destroy(mCairoFont
);
596 gfxPangoFont::Shutdown()
598 gfxPangoFontCache::Shutdown();
600 // This just cleans up memory used by Pango's caches and may cause an
601 // assert and crash in cairo (Bug 399556), so only do this when we care
602 // about cleaning up memory on shutdown.
603 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(NS_TRACE_MALLOC)
604 PangoFontMap
*fontmap
= pango_cairo_font_map_get_default ();
605 if (PANGO_IS_FC_FONT_MAP (fontmap
))
606 pango_fc_font_map_shutdown (PANGO_FC_FONT_MAP (fontmap
));
611 ThebesStyleToPangoStyle (const gfxFontStyle
*fs
)
613 if (fs
->style
== FONT_STYLE_ITALIC
)
614 return PANGO_STYLE_ITALIC
;
615 if (fs
->style
== FONT_STYLE_OBLIQUE
)
616 return PANGO_STYLE_OBLIQUE
;
618 return PANGO_STYLE_NORMAL
;
622 PangoStyleToThebesStyle (PangoStyle aPangoStyle
)
624 if (aPangoStyle
== PANGO_STYLE_ITALIC
)
625 return FONT_STYLE_ITALIC
;
626 if (aPangoStyle
== FONT_STYLE_OBLIQUE
)
627 return FONT_STYLE_OBLIQUE
;
629 return FONT_STYLE_NORMAL
;
633 ThebesStyleToPangoWeight (const gfxFontStyle
*fs
)
635 PRInt32 w
= fs
->weight
;
638 * weights come in two parts crammed into one
639 * integer -- the "base" weight is weight / 100,
640 * the rest of the value is the "offset" from that
641 * weight -- the number of steps to move to adjust
642 * the weight in the list of supported font weights,
643 * this value can be negative or positive.
645 PRInt32 baseWeight
= (w
+ 50) / 100;
646 PRInt32 offset
= w
- baseWeight
* 100;
648 /* clip weights to range 0 to 9 */
654 /* Map from weight value to fcWeights index */
655 static const int fcWeightLookup
[10] = {
656 0, 0, 0, 0, 1, 1, 2, 3, 3, 4,
659 PRInt32 fcWeight
= fcWeightLookup
[baseWeight
];
662 * adjust by the offset value, make sure we stay inside the
672 /* Map to final PANGO_WEIGHT value */
673 static const int fcWeights
[5] = {
681 return (PangoWeight
)fcWeights
[fcWeight
];
684 /* Note this doesn't check sizeAdjust */
685 static PangoFontDescription
*
686 NewPangoFontDescription(const nsAString
&aName
, const gfxFontStyle
*aFontStyle
)
688 PangoFontDescription
*fontDesc
= pango_font_description_new();
690 pango_font_description_set_family(fontDesc
,
691 NS_ConvertUTF16toUTF8(aName
).get());
692 pango_font_description_set_absolute_size(fontDesc
,
693 aFontStyle
->size
* PANGO_SCALE
);
694 pango_font_description_set_style(fontDesc
,
695 ThebesStyleToPangoStyle(aFontStyle
));
696 pango_font_description_set_weight(fontDesc
,
697 ThebesStyleToPangoWeight(aFontStyle
));
702 * The following gfxPangoFonts are accessed from the PangoFont, not from the
703 * gfxFontCache hash table. The gfxFontCache hash table is keyed by desired
704 * family and style, whereas here we only know actual family and style. There
705 * may be more than one of these fonts with the same family and style, but
706 * different PangoFont and actual font face.
708 * The point of this is to record the exact font face for gfxTextRun glyph
709 * indices. The style of this font does not necessarily represent the exact
710 * gfxFontStyle used to build the text run. Notably, the language is not
711 * recorded, but is used for GetMetrics().aveCharWidth. However, the font
712 * that should be used for aveCharWidth is gfxPangoFontGroup::GetFontAt(0),
713 * which is not constructed here.
717 already_AddRefed
<gfxPangoFont
>
718 gfxPangoFont::GetOrMakeFont(PangoFont
*aPangoFont
)
720 gfxPangoFont
*font
= static_cast<gfxPangoFont
*>
721 (g_object_get_qdata(G_OBJECT(aPangoFont
), GetFontQuark()));
724 // pango_font_describe_with_absolute_size requires Pango-1.14
725 PangoFontDescription
*desc
= pango_font_describe(aPangoFont
);
727 PangoFcFont
*fcfont
= PANGO_FC_FONT(aPangoFont
);
729 if (FcPatternGetDouble(fcfont
->font_pattern
, FC_PIXEL_SIZE
, 0, &size
)
731 size
= pango_font_description_get_size(desc
) / FLOAT_PANGO_SCALE
;
733 // Shouldn't actually need to take too much care about the correct
734 // family or style, as size is the only thing expected to be
737 PangoStyleToThebesStyle(pango_font_description_get_style(desc
));
738 PRUint16 weight
= pango_font_description_get_weight(desc
);
739 NS_NAMED_LITERAL_CSTRING(langGroup
, "x-unicode");
740 gfxFontStyle
fontStyle(style
, weight
, size
, langGroup
, 0.0,
743 // (The PangoFontDescription owns the family string)
744 const char *family
= pango_font_description_get_family(desc
);
745 font
= new gfxPangoFont(aPangoFont
,
746 NS_ConvertUTF8toUTF16(family
), &fontStyle
);
748 pango_font_description_free(desc
);
752 // Do not add this font to the gfxFontCache hash table as this may not
753 // be the PangoFont that fontconfig chooses for this style.
760 LoadPangoFont(PangoContext
*aPangoCtx
, const PangoFontDescription
*aPangoFontDesc
)
762 gfxPangoFontCache
*cache
= gfxPangoFontCache::GetPangoFontCache();
764 return nsnull
; // Error
765 PangoFont
* pangoFont
= cache
->Get(aPangoFontDesc
);
767 pangoFont
= pango_context_load_font(aPangoCtx
, aPangoFontDesc
);
769 cache
->Put(aPangoFontDesc
, pangoFont
);
776 gfxPangoFont::RealizePangoFont()
782 PangoFontDescription
*pangoFontDesc
=
783 NewPangoFontDescription(mName
, GetStyle());
785 PangoContext
*pangoCtx
= gdk_pango_context_get();
787 if (!GetStyle()->langGroup
.IsEmpty()) {
788 PangoLanguage
*lang
= GetPangoLanguage(GetStyle()->langGroup
);
790 pango_context_set_language(pangoCtx
, lang
);
793 mPangoFont
= LoadPangoFont(pangoCtx
, pangoFontDesc
);
795 gfxFloat size
= GetStyle()->size
;
796 // Checking mPangoFont to avoid infinite recursion through GetCharSize
797 if (size
!= 0.0 && GetStyle()->sizeAdjust
!= 0.0 && mPangoFont
) {
798 // Could try xHeight from TrueType/OpenType fonts.
800 GetCharSize('x', isz
, lsz
);
801 if (isz
.height
!= 0.0) {
802 gfxFloat aspect
= isz
.height
/ size
;
803 size
= GetStyle()->GetAdjustedSize(aspect
);
805 pango_font_description_set_absolute_size(pangoFontDesc
,
807 g_object_unref(mPangoFont
);
808 mPangoFont
= LoadPangoFont(pangoCtx
, pangoFontDesc
);
812 NS_ASSERTION(mHasMetrics
== PR_FALSE
, "metrics will be invalid...");
813 mAdjustedSize
= size
;
814 if (!g_object_get_qdata(G_OBJECT(mPangoFont
), GetFontQuark()))
815 g_object_set_qdata(G_OBJECT(mPangoFont
), GetFontQuark(), this);
818 pango_font_description_free(pangoFontDesc
);
820 g_object_unref(pangoCtx
);
824 gfxPangoFont::GetCharSize(char aChar
, gfxSize
& aInkSize
, gfxSize
& aLogSize
,
827 if (NS_UNLIKELY(GetStyle()->size
== 0.0)) {
830 aInkSize
.SizeTo(0.0, 0.0);
831 aLogSize
.SizeTo(0.0, 0.0);
835 // XXXkt: Why not use pango_font_get_glyph_extents? This function isn't
836 // currently being used for characters likely to involve glyph clusters.
837 // I don't think pango_shape will fallback to other fonts.
838 PangoAnalysis analysis
;
839 // Initialize new fields, gravity and flags in pango 1.16
840 // (or padding in 1.14).
841 // Use memset instead of { 0 } aggregate initialization or placement new
842 // default initialization so that padding (which may have meaning in other
843 // versions) is initialized.
844 memset(&analysis
, 0, sizeof(analysis
));
845 analysis
.font
= GetPangoFont();
846 analysis
.language
= pango_language_from_string("en");
847 analysis
.shape_engine
= pango_font_find_shaper(analysis
.font
, analysis
.language
, aChar
);
849 PangoGlyphString
*glstr
= pango_glyph_string_new();
850 pango_shape (&aChar
, 1, &analysis
, glstr
);
854 if (glstr
->num_glyphs
== 1) {
855 PangoGlyph glyph
= glstr
->glyphs
[0].glyph
;
856 if (!IS_MISSING_GLYPH(glyph
) && !IS_EMPTY_GLYPH(glyph
)) {
862 PangoRectangle ink_rect
, log_rect
;
863 pango_glyph_string_extents(glstr
, analysis
.font
, &ink_rect
, &log_rect
);
865 aInkSize
.width
= ink_rect
.width
/ FLOAT_PANGO_SCALE
;
866 aInkSize
.height
= ink_rect
.height
/ FLOAT_PANGO_SCALE
;
868 aLogSize
.width
= log_rect
.width
/ FLOAT_PANGO_SCALE
;
869 aLogSize
.height
= log_rect
.height
/ FLOAT_PANGO_SCALE
;
871 pango_glyph_string_free(glstr
);
874 // rounding and truncation functions for a Freetype fixed point number
875 // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
876 // part and low 6 bits for the fractional part.
877 #define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
878 #define MOZ_FT_TRUNC(x) ((x) >> 6)
879 #define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
880 MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
882 const gfxFont::Metrics
&
883 gfxPangoFont::GetMetrics()
888 /* pango_cairo case; try to get all the metrics from pango itself */
890 PangoFontMetrics
*pfm
;
891 if (NS_LIKELY(GetStyle()->size
> 0.0)) {
892 font
= GetPangoFont(); // RealizePangoFont is called here.
893 PangoLanguage
*lang
= GetPangoLanguage(GetStyle()->langGroup
);
894 // If lang is NULL, Pango will measure a string of many languages,
895 // which will require many FcFontSorts, but we don't want to go to
896 // that much trouble.
897 // pango_language_get_default() is available from Pango-1.16.
899 lang
= pango_language_from_string(setlocale(LC_CTYPE
, NULL
));
901 pfm
= pango_font_get_metrics(font
, lang
);
903 // Don't ask pango when the font-size is zero since it causes
904 // some versions of libpango to crash (bug 404112).
909 if (NS_LIKELY(pfm
)) {
911 pango_font_metrics_get_ascent(pfm
) / FLOAT_PANGO_SCALE
;
913 mMetrics
.maxDescent
=
914 pango_font_metrics_get_descent(pfm
) / FLOAT_PANGO_SCALE
;
916 // This is used for the width of text input elements so be liberal
917 // rather than conservative in the estimate.
918 mMetrics
.aveCharWidth
=
919 PR_MAX(pango_font_metrics_get_approximate_char_width(pfm
),
920 pango_font_metrics_get_approximate_digit_width(pfm
))
923 mMetrics
.underlineOffset
=
924 pango_font_metrics_get_underline_position(pfm
) / FLOAT_PANGO_SCALE
;
926 mMetrics
.underlineSize
=
927 pango_font_metrics_get_underline_thickness(pfm
) / FLOAT_PANGO_SCALE
;
929 mMetrics
.strikeoutOffset
=
930 pango_font_metrics_get_strikethrough_position(pfm
) / FLOAT_PANGO_SCALE
;
932 mMetrics
.strikeoutSize
=
933 pango_font_metrics_get_strikethrough_thickness(pfm
) / FLOAT_PANGO_SCALE
;
935 // We're going to overwrite this below if we have a FT_Face
936 // (which we normally should have...).
937 mMetrics
.maxAdvance
= mMetrics
.aveCharWidth
;
939 mMetrics
.maxAscent
= 0.0;
940 mMetrics
.maxDescent
= 0.0;
941 mMetrics
.aveCharWidth
= 0.0;
942 mMetrics
.underlineOffset
= -1.0;
943 mMetrics
.underlineSize
= 0.0;
944 mMetrics
.strikeoutOffset
= 0.0;
945 mMetrics
.strikeoutSize
= 0.0;
946 mMetrics
.maxAdvance
= 0.0;
950 mMetrics
.emHeight
= mAdjustedSize
;
952 gfxFloat lineHeight
= mMetrics
.maxAscent
+ mMetrics
.maxDescent
;
953 if (lineHeight
> mMetrics
.emHeight
)
954 mMetrics
.externalLeading
= lineHeight
- mMetrics
.emHeight
;
956 mMetrics
.externalLeading
= 0;
957 mMetrics
.internalLeading
= 0;
959 mMetrics
.maxHeight
= lineHeight
;
961 mMetrics
.emAscent
= lineHeight
> 0.0 ?
962 mMetrics
.maxAscent
* mMetrics
.emHeight
/ lineHeight
: 0.0;
963 mMetrics
.emDescent
= mMetrics
.emHeight
- mMetrics
.emAscent
;
966 GetCharSize(' ', isz
, lsz
, &mSpaceGlyph
);
967 mMetrics
.spaceWidth
= lsz
.width
;
968 GetCharSize('x', isz
, lsz
);
969 mMetrics
.xHeight
= isz
.height
;
972 if (pfm
&& PANGO_IS_FC_FONT(font
))
973 face
= pango_fc_font_lock_face(PANGO_FC_FONT(font
));
976 mMetrics
.maxAdvance
= face
->size
->metrics
.max_advance
/ 64.0; // 26.6
980 TT_OS2
*os2
= (TT_OS2
*) FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
982 if (os2
&& os2
->ySuperscriptYOffset
) {
983 val
= CONVERT_DESIGN_UNITS_TO_PIXELS(os2
->ySuperscriptYOffset
,
984 face
->size
->metrics
.y_scale
);
985 mMetrics
.superscriptOffset
= PR_MAX(1, val
);
987 mMetrics
.superscriptOffset
= mMetrics
.xHeight
;
990 if (os2
&& os2
->ySubscriptYOffset
) {
991 val
= CONVERT_DESIGN_UNITS_TO_PIXELS(os2
->ySubscriptYOffset
,
992 face
->size
->metrics
.y_scale
);
993 // some fonts have the incorrect sign.
994 val
= (val
< 0) ? -val
: val
;
995 mMetrics
.subscriptOffset
= PR_MAX(1, val
);
997 mMetrics
.subscriptOffset
= mMetrics
.xHeight
;
1000 pango_fc_font_unlock_face(PANGO_FC_FONT(font
));
1002 mMetrics
.superscriptOffset
= mMetrics
.xHeight
;
1003 mMetrics
.subscriptOffset
= mMetrics
.xHeight
;
1006 SanitizeMetrics(&mMetrics
, PR_FALSE
);
1009 // printf("font name: %s %f %f\n", NS_ConvertUTF16toUTF8(mName).get(), GetStyle()->size, mAdjustedSize);
1010 // printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
1012 fprintf (stderr
, "Font: %s\n", NS_ConvertUTF16toUTF8(mName
).get());
1013 fprintf (stderr
, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics
.emHeight
, mMetrics
.emAscent
, mMetrics
.emDescent
);
1014 fprintf (stderr
, " maxAscent: %f maxDescent: %f\n", mMetrics
.maxAscent
, mMetrics
.maxDescent
);
1015 fprintf (stderr
, " internalLeading: %f externalLeading: %f\n", mMetrics
.externalLeading
, mMetrics
.internalLeading
);
1016 fprintf (stderr
, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics
.spaceWidth
, mMetrics
.aveCharWidth
, mMetrics
.xHeight
);
1017 fprintf (stderr
, " uOff: %f uSize: %f stOff: %f stSize: %f suOff: %f suSize: %f\n", mMetrics
.underlineOffset
, mMetrics
.underlineSize
, mMetrics
.strikeoutOffset
, mMetrics
.strikeoutSize
, mMetrics
.superscriptOffset
, mMetrics
.subscriptOffset
);
1021 pango_font_metrics_unref(pfm
);
1023 mHasMetrics
= PR_TRUE
;
1028 gfxPangoFont::GetGlyph(const PRUint32 aChar
)
1030 // Ensure that null character should be missing.
1033 return pango_fc_font_get_glyph(PANGO_FC_FONT(GetPangoFont()), aChar
);
1037 gfxPangoFont::GetUniqueName()
1039 PangoFont
*font
= GetPangoFont();
1040 PangoFontDescription
*desc
= pango_font_describe(font
);
1041 pango_font_description_unset_fields (desc
, PANGO_FONT_MASK_SIZE
);
1042 char *str
= pango_font_description_to_string(desc
);
1043 pango_font_description_free (desc
);
1046 CopyUTF8toUTF16(str
, result
);
1054 * Some serious problems:
1056 * -- We draw with a font that's hinted for the CTM, but we measure with a font
1057 * hinted to the identity matrix, so our "bounding metrics" may not be accurate.
1059 * -- CreateScaledFont doesn't necessarily give us the font that the Pango
1065 * We use this to append an LTR or RTL Override character to the start of the
1066 * string. This forces Pango to honour our direction even if there are neutral characters
1069 static PRInt32
AppendDirectionalIndicatorUTF8(PRBool aIsRTL
, nsACString
& aString
)
1071 static const PRUnichar overrides
[2][2] =
1072 { { 0x202d, 0 }, { 0x202e, 0 }}; // LRO, RLO
1073 AppendUTF16toUTF8(overrides
[aIsRTL
], aString
);
1074 return 3; // both overrides map to 3 bytes in UTF8
1078 gfxPangoFontGroup::MakeTextRun(const PRUint8
*aString
, PRUint32 aLength
,
1079 const Parameters
*aParams
, PRUint32 aFlags
)
1081 NS_ASSERTION(aFlags
& TEXT_IS_8BIT
, "8bit should have been set");
1082 gfxTextRun
*run
= gfxTextRun::Create(aParams
, aString
, aLength
, this, aFlags
);
1086 PRBool isRTL
= run
->IsRightToLeft();
1087 if ((aFlags
& TEXT_IS_ASCII
) && !isRTL
) {
1088 // We don't need to send an override character here, the characters must be all LTR
1089 const gchar
*utf8Chars
= reinterpret_cast<const gchar
*>(aString
);
1090 InitTextRun(run
, utf8Chars
, aLength
, 0, PR_TRUE
);
1092 // this is really gross...
1093 const char *chars
= reinterpret_cast<const char*>(aString
);
1094 NS_ConvertASCIItoUTF16
unicodeString(chars
, aLength
);
1096 PRInt32 headerLen
= AppendDirectionalIndicatorUTF8(isRTL
, utf8
);
1097 AppendUTF16toUTF8(unicodeString
, utf8
);
1098 InitTextRun(run
, utf8
.get(), utf8
.Length(), headerLen
, PR_TRUE
);
1100 run
->FetchGlyphExtents(aParams
->mContext
);
1104 #if defined(ENABLE_FAST_PATH_8BIT)
1106 gfxPangoFontGroup::CanTakeFastPath(PRUint32 aFlags
)
1108 // Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't.
1109 // We need to always use Pango for RTL text, in case glyph mirroring is
1111 PRBool speed
= aFlags
& gfxTextRunFactory::TEXT_OPTIMIZE_SPEED
;
1112 PRBool isRTL
= aFlags
& gfxTextRunFactory::TEXT_IS_RTL
;
1113 return speed
&& !isRTL
&& PANGO_IS_FC_FONT(GetFontAt(0)->GetPangoFont());
1118 gfxPangoFontGroup::MakeTextRun(const PRUnichar
*aString
, PRUint32 aLength
,
1119 const Parameters
*aParams
, PRUint32 aFlags
)
1121 gfxTextRun
*run
= gfxTextRun::Create(aParams
, aString
, aLength
, this, aFlags
);
1125 run
->RecordSurrogates(aString
);
1128 PRInt32 headerLen
= AppendDirectionalIndicatorUTF8(run
->IsRightToLeft(), utf8
);
1129 AppendUTF16toUTF8(Substring(aString
, aString
+ aLength
), utf8
);
1130 PRBool is8Bit
= PR_FALSE
;
1132 #if defined(ENABLE_FAST_PATH_8BIT)
1133 if (CanTakeFastPath(aFlags
)) {
1134 PRUint32 allBits
= 0;
1136 for (i
= 0; i
< aLength
; ++i
) {
1137 allBits
|= aString
[i
];
1139 is8Bit
= (allBits
& 0xFF00) == 0;
1142 InitTextRun(run
, utf8
.get(), utf8
.Length(), headerLen
, is8Bit
);
1143 run
->FetchGlyphExtents(aParams
->mContext
);
1148 gfxPangoFontGroup::InitTextRun(gfxTextRun
*aTextRun
, const gchar
*aUTF8Text
,
1149 PRUint32 aUTF8Length
, PRUint32 aUTF8HeaderLength
,
1150 PRBool aTake8BitPath
)
1152 #if defined(ENABLE_FAST_PATH_ALWAYS)
1153 CreateGlyphRunsFast(aTextRun
, aUTF8Text
+ aUTF8HeaderLength
, aUTF8Length
- aUTF8HeaderLength
);
1155 #if defined(ENABLE_FAST_PATH_8BIT)
1156 if (aTake8BitPath
&& CanTakeFastPath(aTextRun
->GetFlags())) {
1157 nsresult rv
= CreateGlyphRunsFast(aTextRun
, aUTF8Text
+ aUTF8HeaderLength
, aUTF8Length
- aUTF8HeaderLength
);
1158 if (NS_SUCCEEDED(rv
))
1163 CreateGlyphRunsItemizing(aTextRun
, aUTF8Text
, aUTF8Length
, aUTF8HeaderLength
);
1167 static cairo_scaled_font_t
*
1168 CreateScaledFont(cairo_t
*aCR
, cairo_matrix_t
*aCTM
, PangoFont
*aPangoFont
)
1170 // XXX this needs to also check that we're using system cairo
1171 // otherwise this causes bad problems.
1173 //#if PANGO_VERSION_CHECK(1,17,5)
1174 // Lets just use pango_cairo_font_get_scaled_font() for now. it's only
1175 // available in pango 1.17.x though :(
1176 return cairo_scaled_font_reference (pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (aPangoFont
)));
1178 // XXX is this safe really? We should probably check the font type or something.
1179 // XXX does this really create the same font that Pango used for measurement?
1180 // We probably need to work harder here. We should pay particular attention
1181 // to the font options.
1182 PangoFcFont
*fcfont
= PANGO_FC_FONT(aPangoFont
);
1183 cairo_font_face_t
*face
= cairo_ft_font_face_create_for_pattern(fcfont
->font_pattern
);
1185 if (FcPatternGetDouble(fcfont
->font_pattern
, FC_PIXEL_SIZE
, 0, &size
) != FcResultMatch
)
1187 cairo_matrix_t fontMatrix
;
1189 if (FcPatternGetMatrix(fcfont
->font_pattern
, FC_MATRIX
, 0, &fcMatrix
) == FcResultMatch
)
1190 cairo_matrix_init(&fontMatrix
, fcMatrix
->xx
, -fcMatrix
->yx
, -fcMatrix
->xy
, fcMatrix
->yy
, 0, 0);
1192 cairo_matrix_init_identity(&fontMatrix
);
1193 cairo_matrix_scale(&fontMatrix
, size
, size
);
1194 cairo_font_options_t
*fontOptions
= cairo_font_options_create();
1195 cairo_get_font_options(aCR
, fontOptions
);
1196 cairo_scaled_font_t
*scaledFont
=
1197 cairo_scaled_font_create(face
, &fontMatrix
, aCTM
, fontOptions
);
1198 cairo_font_options_destroy(fontOptions
);
1199 cairo_font_face_destroy(face
);
1200 NS_ASSERTION(cairo_scaled_font_status(scaledFont
) == CAIRO_STATUS_SUCCESS
,
1201 "Failed to create scaled font");
1207 gfxPangoFont::SetupCairoFont(gfxContext
*aContext
)
1209 cairo_t
*cr
= aContext
->GetCairo();
1210 cairo_matrix_t currentCTM
;
1211 cairo_get_matrix(cr
, ¤tCTM
);
1214 // Need to validate that its CTM is OK
1215 cairo_matrix_t fontCTM
;
1216 cairo_scaled_font_get_ctm(mCairoFont
, &fontCTM
);
1217 if (fontCTM
.xx
!= currentCTM
.xx
|| fontCTM
.yy
!= currentCTM
.yy
||
1218 fontCTM
.xy
!= currentCTM
.xy
|| fontCTM
.yx
!= currentCTM
.yx
) {
1219 // Just recreate it from scratch, simplest way
1220 cairo_scaled_font_destroy(mCairoFont
);
1221 mCairoFont
= nsnull
;
1225 mCairoFont
= CreateScaledFont(cr
, ¤tCTM
, GetPangoFont());
1227 if (cairo_scaled_font_status(mCairoFont
) != CAIRO_STATUS_SUCCESS
) {
1228 // Don't cairo_set_scaled_font as that would propagate the error to
1229 // the cairo_t, precluding any further drawing.
1232 cairo_set_scaled_font(cr
, mCairoFont
);
1237 SetupClusterBoundaries(gfxTextRun
* aTextRun
, const gchar
*aUTF8
, PRUint32 aUTF8Length
,
1238 PRUint32 aUTF16Offset
, PangoAnalysis
*aAnalysis
)
1240 if (aTextRun
->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT
) {
1241 // 8-bit text doesn't have clusters.
1242 // XXX is this true in all languages???
1243 // behdad: don't think so. Czech for example IIRC has a
1248 // Pango says "the array of PangoLogAttr passed in must have at least N+1
1249 // elements, if there are N characters in the text being broken".
1250 // Could use g_utf8_strlen(aUTF8, aUTF8Length) + 1 but the memory savings
1251 // may not be worth the call.
1252 nsAutoTArray
<PangoLogAttr
,2000> buffer
;
1253 if (!buffer
.AppendElements(aUTF8Length
+ 1))
1256 pango_break(aUTF8
, aUTF8Length
, aAnalysis
,
1257 buffer
.Elements(), buffer
.Length());
1259 const gchar
*p
= aUTF8
;
1260 const gchar
*end
= aUTF8
+ aUTF8Length
;
1261 const PangoLogAttr
*attr
= buffer
.Elements();
1262 gfxTextRun::CompressedGlyph g
;
1264 if (!attr
->is_cursor_position
) {
1265 aTextRun
->SetGlyphs(aUTF16Offset
, g
.SetComplex(PR_FALSE
, PR_TRUE
, 0), nsnull
);
1269 gunichar ch
= g_utf8_get_char(p
);
1270 NS_ASSERTION(ch
!= 0, "Shouldn't have NUL in pango_break");
1271 NS_ASSERTION(!IS_SURROGATE(ch
), "Shouldn't have surrogates in UTF8");
1272 if (ch
>= 0x10000) {
1275 // We produced this utf8 so we don't need to worry about malformed stuff
1276 p
= g_utf8_next_char(p
);
1282 ConvertPangoToAppUnits(PRInt32 aCoordinate
, PRUint32 aAppUnitsPerDevUnit
)
1284 PRInt64 v
= (PRInt64(aCoordinate
)*aAppUnitsPerDevUnit
+ PANGO_SCALE
/2)/PANGO_SCALE
;
1289 * Given a run of Pango glyphs that should be treated as a single
1290 * cluster/ligature, store them in the textrun at the appropriate character
1291 * and set the other characters involved to be ligature/cluster continuations
1295 SetGlyphsForCharacterGroup(const PangoGlyphInfo
*aGlyphs
, PRUint32 aGlyphCount
,
1296 gfxTextRun
*aTextRun
,
1297 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
1298 PRUint32
*aUTF16Offset
,
1299 PangoGlyphUnit aOverrideSpaceWidth
)
1301 PRUint32 utf16Offset
= *aUTF16Offset
;
1302 PRUint32 textRunLength
= aTextRun
->GetLength();
1303 const PRUint32 appUnitsPerDevUnit
= aTextRun
->GetAppUnitsPerDevUnit();
1304 const gfxTextRun::CompressedGlyph
*charGlyphs
= aTextRun
->GetCharacterGlyphs();
1306 // Override the width of a space, but only for spaces that aren't
1307 // clustered with something else (like a freestanding diacritical mark)
1308 PangoGlyphUnit width
= aGlyphs
[0].geometry
.width
;
1309 if (aOverrideSpaceWidth
&& aUTF8
[0] == ' ' &&
1310 (utf16Offset
+ 1 == textRunLength
||
1311 charGlyphs
[utf16Offset
].IsClusterStart())) {
1312 width
= aOverrideSpaceWidth
;
1314 PRInt32 advance
= ConvertPangoToAppUnits(width
, appUnitsPerDevUnit
);
1316 gfxTextRun::CompressedGlyph g
;
1317 PRBool atClusterStart
= aTextRun
->IsClusterStart(utf16Offset
);
1318 // See if we fit in the compressed area.
1319 if (aGlyphCount
== 1 && advance
>= 0 && atClusterStart
&&
1320 aGlyphs
[0].geometry
.x_offset
== 0 &&
1321 aGlyphs
[0].geometry
.y_offset
== 0 &&
1322 gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance
) &&
1323 gfxTextRun::CompressedGlyph::IsSimpleGlyphID(aGlyphs
[0].glyph
)) {
1324 aTextRun
->SetSimpleGlyph(utf16Offset
,
1325 g
.SetSimpleGlyph(advance
, aGlyphs
[0].glyph
));
1327 nsAutoTArray
<gfxTextRun::DetailedGlyph
,10> detailedGlyphs
;
1328 if (!detailedGlyphs
.AppendElements(aGlyphCount
))
1329 return NS_ERROR_OUT_OF_MEMORY
;
1332 for (i
= 0; i
< aGlyphCount
; ++i
) {
1333 gfxTextRun::DetailedGlyph
*details
= &detailedGlyphs
[i
];
1334 PRUint32 j
= (aTextRun
->IsRightToLeft()) ? aGlyphCount
- 1 - i
: i
;
1335 const PangoGlyphInfo
&glyph
= aGlyphs
[j
];
1336 details
->mGlyphID
= glyph
.glyph
;
1337 NS_ASSERTION(details
->mGlyphID
== glyph
.glyph
,
1338 "Seriously weird glyph ID detected!");
1340 ConvertPangoToAppUnits(glyph
.geometry
.width
,
1341 appUnitsPerDevUnit
);
1343 float(glyph
.geometry
.x_offset
)*appUnitsPerDevUnit
/PANGO_SCALE
;
1345 float(glyph
.geometry
.y_offset
)*appUnitsPerDevUnit
/PANGO_SCALE
;
1347 g
.SetComplex(atClusterStart
, PR_TRUE
, aGlyphCount
);
1348 aTextRun
->SetGlyphs(utf16Offset
, g
, detailedGlyphs
.Elements());
1351 // Check for ligatures and set *aUTF16Offset.
1352 const gchar
*p
= aUTF8
;
1353 const gchar
*end
= aUTF8
+ aUTF8Length
;
1355 // Skip the CompressedGlyph that we have added, but check if the
1356 // character was supposed to be ignored. If it's supposed to be ignored,
1357 // overwrite the textrun entry with an invisible missing-glyph.
1358 gunichar ch
= g_utf8_get_char(p
);
1359 NS_ASSERTION(!IS_SURROGATE(ch
), "surrogates should not appear in UTF8");
1360 if (ch
>= 0x10000) {
1364 NS_ASSERTION(!gfxFontGroup::IsInvalidChar(PRUnichar(ch
)),
1365 "Invalid character detected");
1368 // We produced this UTF8 so we don't need to worry about malformed stuff
1369 p
= g_utf8_next_char(p
);
1373 if (utf16Offset
>= textRunLength
) {
1374 NS_ERROR("Someone has added too many glyphs!");
1375 return NS_ERROR_FAILURE
;
1378 g
.SetComplex(aTextRun
->IsClusterStart(utf16Offset
), PR_FALSE
, 0);
1379 aTextRun
->SetGlyphs(utf16Offset
, g
, nsnull
);
1381 *aUTF16Offset
= utf16Offset
;
1386 gfxPangoFontGroup::SetGlyphs(gfxTextRun
*aTextRun
, gfxPangoFont
*aFont
,
1387 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
1388 PRUint32
*aUTF16Offset
, PangoGlyphString
*aGlyphs
,
1389 PangoGlyphUnit aOverrideSpaceWidth
,
1390 PRBool aAbortOnMissingGlyph
)
1392 gint numGlyphs
= aGlyphs
->num_glyphs
;
1393 PangoGlyphInfo
*glyphs
= aGlyphs
->glyphs
;
1394 const gint
*logClusters
= aGlyphs
->log_clusters
;
1395 // We cannot make any assumptions about the order of glyph clusters
1396 // provided by pango_shape (see 375864), so we work through the UTF8 text
1397 // and process the glyph clusters in logical order.
1399 // logGlyphs is like an inverse of logClusters. For each UTF8 byte:
1400 // >= 0 indicates that the byte is first in a cluster and
1401 // gives the position of the starting glyph for the cluster.
1402 // -1 indicates that the byte does not start a cluster.
1403 nsAutoTArray
<gint
,2000> logGlyphs
;
1404 if (!logGlyphs
.AppendElements(aUTF8Length
+ 1))
1405 return NS_ERROR_OUT_OF_MEMORY
;
1406 PRUint32 utf8Index
= 0;
1407 for(; utf8Index
< aUTF8Length
; ++utf8Index
)
1408 logGlyphs
[utf8Index
] = -1;
1409 logGlyphs
[aUTF8Length
] = numGlyphs
;
1411 gint lastCluster
= -1; // != utf8Index
1412 for (gint glyphIndex
= 0; glyphIndex
< numGlyphs
; ++glyphIndex
) {
1413 gint thisCluster
= logClusters
[glyphIndex
];
1414 if (thisCluster
!= lastCluster
) {
1415 lastCluster
= thisCluster
;
1416 NS_ASSERTION(0 <= thisCluster
&& thisCluster
< gint(aUTF8Length
),
1417 "garbage from pango_shape - this is bad");
1418 logGlyphs
[thisCluster
] = glyphIndex
;
1422 PRUint32 utf16Offset
= *aUTF16Offset
;
1423 PRUint32 textRunLength
= aTextRun
->GetLength();
1425 // The next glyph cluster in logical order.
1426 gint nextGlyphClusterStart
= logGlyphs
[utf8Index
];
1427 NS_ASSERTION(nextGlyphClusterStart
>= 0, "No glyphs! - NUL in string?");
1428 while (utf8Index
< aUTF8Length
) {
1429 if (utf16Offset
>= textRunLength
) {
1430 NS_ERROR("Someone has added too many glyphs!");
1431 return NS_ERROR_FAILURE
;
1433 gint glyphClusterStart
= nextGlyphClusterStart
;
1434 // Find the utf8 text associated with this glyph cluster.
1435 PRUint32 clusterUTF8Start
= utf8Index
;
1436 // Check we are consistent with pango_break data.
1437 NS_ASSERTION(aTextRun
->GetCharacterGlyphs()->IsClusterStart(),
1438 "Glyph cluster not aligned on character cluster.");
1441 nextGlyphClusterStart
= logGlyphs
[utf8Index
];
1442 } while (nextGlyphClusterStart
< 0);
1443 const gchar
*clusterUTF8
= &aUTF8
[clusterUTF8Start
];
1444 PRUint32 clusterUTF8Length
= utf8Index
- clusterUTF8Start
;
1446 PRBool haveMissingGlyph
= PR_FALSE
;
1447 gint glyphIndex
= glyphClusterStart
;
1449 // It's now unncecessary to do NUL handling here.
1451 if (IS_EMPTY_GLYPH(glyphs
[glyphIndex
].glyph
)) {
1452 // The zero width characters return empty glyph ID at
1453 // shaping, we should override it.
1454 glyphs
[glyphIndex
].glyph
= aFont
->GetGlyph(' ');
1455 glyphs
[glyphIndex
].geometry
.width
= 0;
1456 } else if (IS_MISSING_GLYPH(glyphs
[glyphIndex
].glyph
)) {
1457 // Does pango ever provide more than one glyph in the
1458 // cluster if there is a missing glyph?
1460 haveMissingGlyph
= PR_TRUE
;
1463 } while (glyphIndex
< numGlyphs
&&
1464 logClusters
[glyphIndex
] == gint(clusterUTF8Start
));
1466 if (haveMissingGlyph
&& aAbortOnMissingGlyph
)
1467 return NS_ERROR_FAILURE
;
1470 if (haveMissingGlyph
) {
1471 rv
= SetMissingGlyphs(aTextRun
, clusterUTF8
, clusterUTF8Length
,
1474 rv
= SetGlyphsForCharacterGroup(&glyphs
[glyphClusterStart
],
1475 glyphIndex
- glyphClusterStart
,
1477 clusterUTF8
, clusterUTF8Length
,
1478 &utf16Offset
, aOverrideSpaceWidth
);
1480 NS_ENSURE_SUCCESS(rv
,rv
);
1482 *aUTF16Offset
= utf16Offset
;
1487 gfxPangoFontGroup::SetMissingGlyphs(gfxTextRun
*aTextRun
,
1488 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
1489 PRUint32
*aUTF16Offset
)
1491 PRUint32 utf16Offset
= *aUTF16Offset
;
1492 PRUint32 textRunLength
= aTextRun
->GetLength();
1493 for (PRUint32 index
= 0; index
< aUTF8Length
;) {
1494 if (utf16Offset
>= textRunLength
) {
1495 NS_ERROR("Someone has added too many glyphs!");
1498 gunichar ch
= g_utf8_get_char(aUTF8
+ index
);
1499 aTextRun
->SetMissingGlyph(utf16Offset
, ch
);
1502 NS_ASSERTION(!IS_SURROGATE(ch
), "surrogates should not appear in UTF8");
1505 // We produced this UTF8 so we don't need to worry about malformed stuff
1506 index
= g_utf8_next_char(aUTF8
+ index
) - aUTF8
;
1509 *aUTF16Offset
= utf16Offset
;
1513 #if defined(ENABLE_FAST_PATH_8BIT) || defined(ENABLE_FAST_PATH_ALWAYS)
1515 gfxPangoFontGroup::CreateGlyphRunsFast(gfxTextRun
*aTextRun
,
1516 const gchar
*aUTF8
, PRUint32 aUTF8Length
)
1518 const gchar
*p
= aUTF8
;
1519 gfxPangoFont
*font
= GetFontAt(0);
1520 PangoFont
*pangofont
= font
->GetPangoFont();
1521 PangoFcFont
*fcfont
= PANGO_FC_FONT (pangofont
);
1522 PRUint32 utf16Offset
= 0;
1523 gfxTextRun::CompressedGlyph g
;
1524 const PRUint32 appUnitsPerDevUnit
= aTextRun
->GetAppUnitsPerDevUnit();
1526 aTextRun
->AddGlyphRun(font
, 0);
1528 while (p
< aUTF8
+ aUTF8Length
) {
1529 // glib-2.12.9: "If p does not point to a valid UTF-8 encoded
1530 // character, results are undefined." so it is not easy to assert that
1531 // aUTF8 in fact points to UTF8 data but asserting
1532 // g_unichar_validate(ch) may be mildly useful.
1533 gunichar ch
= g_utf8_get_char(p
);
1534 p
= g_utf8_next_char(p
);
1537 // treat this null byte as a missing glyph. Pango
1538 // doesn't create glyphs for these, not even missing-glyphs.
1539 aTextRun
->SetMissingGlyph(utf16Offset
, 0);
1541 NS_ASSERTION(!IsInvalidChar(ch
), "Invalid char detected");
1542 FT_UInt glyph
= pango_fc_font_get_glyph (fcfont
, ch
);
1543 if (!glyph
) // character not in font,
1544 return NS_ERROR_FAILURE
; // fallback to CreateGlyphRunsItemizing
1546 PangoRectangle rect
;
1547 pango_font_get_glyph_extents (pangofont
, glyph
, NULL
, &rect
);
1549 PRInt32 advance
= PANGO_PIXELS (rect
.width
* appUnitsPerDevUnit
);
1551 gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance
) &&
1552 gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph
)) {
1553 aTextRun
->SetSimpleGlyph(utf16Offset
,
1554 g
.SetSimpleGlyph(advance
, glyph
));
1556 gfxTextRun::DetailedGlyph details
;
1557 details
.mGlyphID
= glyph
;
1558 NS_ASSERTION(details
.mGlyphID
== glyph
,
1559 "Seriously weird glyph ID detected!");
1560 details
.mAdvance
= advance
;
1561 details
.mXOffset
= 0;
1562 details
.mYOffset
= 0;
1563 g
.SetComplex(aTextRun
->IsClusterStart(utf16Offset
), PR_TRUE
, 1);
1564 aTextRun
->SetGlyphs(utf16Offset
, g
, &details
);
1567 NS_ASSERTION(!IS_SURROGATE(ch
), "Surrogates shouldn't appear in UTF8");
1568 if (ch
>= 0x10000) {
1569 // This character is a surrogate pair in UTF16
1581 SetBaseFont(PangoContext
*aContext
, PangoFont
*aBaseFont
)
1583 PangoFontMap
*fontmap
= pango_context_get_font_map(aContext
);
1584 if (GFX_IS_PANGO_FONT_MAP(fontmap
)) {
1585 // Update the base font in the gfxPangoFontMap
1586 GFX_PANGO_FONT_MAP(fontmap
)->SetBaseFont(aBaseFont
);
1588 else if (aBaseFont
) {
1589 // Change the font map to record and activate the base font
1590 fontmap
= gfxPangoFontMap::NewFontMap(fontmap
, aBaseFont
);
1591 pango_context_set_font_map(aContext
, fontmap
);
1592 g_object_unref(fontmap
);
1597 gfxPangoFontGroup::CreateGlyphRunsItemizing(gfxTextRun
*aTextRun
,
1598 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
1599 PRUint32 aUTF8HeaderLen
)
1602 PangoContext
*context
= gdk_pango_context_get();
1604 PangoFontDescription
*fontDesc
=
1605 NewPangoFontDescription(GetFontAt(0)->GetName(), GetStyle());
1606 if (GetStyle()->sizeAdjust
!= 0.0) {
1608 static_cast<gfxPangoFont
*>(GetFontAt(0))->GetAdjustedSize();
1609 pango_font_description_set_absolute_size(fontDesc
, size
* PANGO_SCALE
);
1612 pango_context_set_font_description(context
, fontDesc
);
1613 pango_font_description_free(fontDesc
);
1615 PangoLanguage
*lang
= GetPangoLanguage(GetStyle()->langGroup
);
1617 // we should set this to null if we don't have a text language from the page...
1618 // except that we almost always have something...
1619 pango_context_set_language(context
, lang
);
1621 // Set the primary font for consistent font selection for common
1622 // characters, but use the default Pango behavior
1623 // (selecting generic fonts from the script of the characters)
1624 // in two situations:
1625 // 1. When we don't have a language to make a good choice for the
1627 // 2. For system fonts, use the default Pango behavior
1628 // to give consistency with other apps.
1629 if (lang
&& !GetStyle()->systemFont
) {
1630 SetBaseFont(context
, GetFontAt(0)->GetPangoFont());
1633 PangoDirection dir
= aTextRun
->IsRightToLeft() ? PANGO_DIRECTION_RTL
: PANGO_DIRECTION_LTR
;
1634 GList
*items
= pango_itemize_with_base_dir(context
, dir
, aUTF8
, 0, aUTF8Length
, nsnull
, nsnull
);
1636 PRUint32 utf16Offset
= 0;
1637 PRBool isRTL
= aTextRun
->IsRightToLeft();
1639 PangoGlyphString
*glyphString
= pango_glyph_string_new();
1643 for (; pos
&& pos
->data
; pos
= pos
->next
) {
1644 PangoItem
*item
= (PangoItem
*)pos
->data
;
1645 NS_ASSERTION(isRTL
== item
->analysis
.level
% 2, "RTL assumption mismatch");
1647 PRUint32 offset
= item
->offset
;
1648 PRUint32 length
= item
->length
;
1649 if (offset
< aUTF8HeaderLen
) {
1650 if (offset
+ length
<= aUTF8HeaderLen
)
1653 length
-= aUTF8HeaderLen
- offset
;
1654 offset
= aUTF8HeaderLen
;
1657 /* look up the gfxPangoFont from the PangoFont */
1658 nsRefPtr
<gfxPangoFont
> font
=
1659 gfxPangoFont::GetOrMakeFont(item
->analysis
.font
);
1661 nsresult rv
= aTextRun
->AddGlyphRun(font
, utf16Offset
, PR_TRUE
);
1662 if (NS_FAILED(rv
)) {
1663 NS_ERROR("AddGlyphRun Failed");
1667 PRUint32 spaceWidth
= NS_lround(font
->GetMetrics().spaceWidth
* FLOAT_PANGO_SCALE
);
1669 const gchar
*p
= aUTF8
+ offset
;
1670 const gchar
*end
= p
+ length
;
1673 aTextRun
->SetMissingGlyph(utf16Offset
, 0);
1679 // It's necessary to loop over pango_shape as it treats
1680 // NULs as string terminators
1681 const gchar
*text
= p
;
1684 } while(p
< end
&& *p
!= 0);
1685 gint len
= p
- text
;
1687 pango_shape(text
, len
, &item
->analysis
, glyphString
);
1688 SetupClusterBoundaries(aTextRun
, text
, len
, utf16Offset
, &item
->analysis
);
1689 SetGlyphs(aTextRun
, font
, text
, len
, &utf16Offset
, glyphString
, spaceWidth
, PR_FALSE
);
1693 aTextRun
->SortGlyphRuns();
1697 pango_glyph_string_free(glyphString
);
1699 for (pos
= items
; pos
; pos
= pos
->next
)
1700 pango_item_free((PangoItem
*)pos
->data
);
1705 g_object_unref(context
);
1711 ** language group helpers
1714 struct MozPangoLangGroup
{
1715 const char *mozLangGroup
;
1716 const char *PangoLang
;
1719 static const MozPangoLangGroup MozPangoLangGroups
[] = {
1720 { "x-western", "en" },
1721 { "x-central-euro", "pl" },
1723 { "zh-TW", "zh-tw" },
1724 { "zh-CN", "zh-cn" },
1725 { "zh-HK", "zh-hk" },
1727 { "x-cyrillic", "ru" },
1728 { "x-baltic", "lv" },
1734 { "x-devanagari", "hi" },
1735 { "x-tamil", "ta" },
1746 { "x-user-def", 0 },
1749 #define NUM_PANGO_LANG_GROUPS (sizeof (MozPangoLangGroups) / \
1750 sizeof (MozPangoLangGroups[0]))
1754 GetPangoLanguage(const nsACString
& cname
)
1756 // see if the lang group needs to be translated from mozilla's
1757 // internal mapping into fontconfig's
1758 const struct MozPangoLangGroup
*langGroup
= nsnull
;
1760 for (unsigned int i
=0; i
< NUM_PANGO_LANG_GROUPS
; ++i
) {
1761 if (cname
.Equals(MozPangoLangGroups
[i
].mozLangGroup
,
1762 nsCaseInsensitiveCStringComparator())) {
1763 langGroup
= &MozPangoLangGroups
[i
];
1768 // if there's no lang group, just use the lang group as it was
1771 // we're casting away the const here for the strings - should be
1774 return pango_language_from_string(nsPromiseFlatCString(cname
).get());
1775 else if (langGroup
->PangoLang
)
1776 return pango_language_from_string(langGroup
->PangoLang
);
1781 // See pango-script-lang-table.h in pango.
1782 static const MozPangoLangGroup PangoAllLangGroup
[] = {
1783 { "x-western", "aa" },
1784 { "x-cyrillic", "ab" },
1785 { "x-western", "af" },
1788 { "x-western", "ast" },
1789 { "x-cyrillic", "ava" },
1790 { "x-western", "ay" },
1791 { "x-western", "az" },
1792 { "x-cyrillic", "ba" },
1793 { "x-western", "bam" },
1794 { "x-cyrillic", "be" },
1795 { "x-cyrillic", "bg" },
1796 { "x-devanagari", "bh" },
1797 { "x-devanagari", "bho" },
1798 { "x-western", "bi" },
1799 { "x-western", "bin" },
1801 { 0, "bo" }, // PANGO_SCRIPT_TIBETAN
1802 { "x-western", "br" },
1803 { "x-western", "bs" },
1804 { "x-cyrillic", "bua" },
1805 { "x-western", "ca" },
1806 { "x-cyrillic", "ce" },
1807 { "x-western", "ch" },
1808 { "x-cyrillic", "chm" },
1809 { 0, "chr" }, // PANGO_SCRIPT_CHEROKEE
1810 { "x-western", "co" },
1811 { "x-central-euro", "cs" }, // PANGO_SCRIPT_LATIN
1812 { "x-cyrillic", "cu" },
1813 { "x-cyrillic", "cv" },
1814 { "x-western", "cy" },
1815 { "x-western", "da" },
1816 { "x-central-euro", "de" }, // PANGO_SCRIPT_LATIN
1817 { 0, "dz" }, // PANGO_SCRIPT_TIBETAN
1819 { "x-western", "en" },
1820 { "x-western", "eo" },
1821 { "x-western", "es" },
1822 { "x-western", "et" },
1823 { "x-western", "eu" },
1825 { "x-western", "fi" },
1826 { "x-western", "fj" },
1827 { "x-western", "fo" },
1828 { "x-western", "fr" },
1829 { "x-western", "ful" },
1830 { "x-western", "fur" },
1831 { "x-western", "fy" },
1832 { "x-western", "ga" },
1833 { "x-western", "gd" },
1834 { "x-ethi", "gez" },
1835 { "x-western", "gl" },
1836 { "x-western", "gn" },
1838 { "x-western", "gv" },
1839 { "x-western", "ha" },
1840 { "x-western", "haw" },
1842 { "x-devanagari", "hi" },
1843 { "x-western", "ho" },
1844 { "x-central-euro", "hr" }, // PANGO_SCRIPT_LATIN
1845 { "x-western", "hu" },
1847 { "x-western", "ia" },
1848 { "x-western", "ibo" },
1849 { "x-western", "id" },
1850 { "x-western", "ie" },
1851 { "x-cyrillic", "ik" },
1852 { "x-western", "io" },
1853 { "x-western", "is" },
1854 { "x-western", "it" },
1858 { "x-cyrillic", "kaa" },
1859 { "x-western", "ki" },
1860 { "x-cyrillic", "kk" },
1861 { "x-western", "kl" },
1863 { 0, "kn" }, // PANGO_SCRIPT_KANNADA
1865 { "x-devanagari", "kok" },
1866 { "x-devanagari", "ks" },
1867 { "x-cyrillic", "ku" },
1868 { "x-cyrillic", "kum" },
1869 { "x-cyrillic", "kv" },
1870 { "x-western", "kw" },
1871 { "x-cyrillic", "ky" },
1872 { "x-western", "la" },
1873 { "x-western", "lb" },
1874 { "x-cyrillic", "lez" },
1875 { 0, "lo" }, // PANGO_SCRIPT_LAO
1876 { "x-western", "lt" },
1877 { "x-western", "lv" },
1878 { "x-western", "mg" },
1879 { "x-western", "mh" },
1880 { "x-western", "mi" },
1881 { "x-cyrillic", "mk" },
1883 { 0, "mn" }, // PANGO_SCRIPT_MONGOLIAN
1884 { "x-western", "mo" },
1885 { "x-devanagari", "mr" },
1886 { "x-western", "mt" },
1887 { 0, "my" }, // PANGO_SCRIPT_MYANMAR
1888 { "x-western", "nb" },
1889 { "x-devanagari", "ne" },
1890 { "x-western", "nl" },
1891 { "x-western", "nn" },
1892 { "x-western", "no" },
1893 { "x-western", "ny" },
1894 { "x-western", "oc" },
1895 { "x-western", "om" },
1896 { 0, "or" }, // PANGO_SCRIPT_ORIYA
1897 { "x-cyrillic", "os" },
1898 { "x-central-euro", "pl" }, // PANGO_SCRIPT_LATIN
1899 { "x-western", "pt" },
1900 { "x-western", "rm" },
1901 { "x-western", "ro" },
1902 { "x-cyrillic", "ru" },
1903 { "x-devanagari", "sa" },
1904 { "x-cyrillic", "sah" },
1905 { "x-western", "sco" },
1906 { "x-western", "se" },
1907 { "x-cyrillic", "sel" },
1908 { "x-cyrillic", "sh" },
1909 { 0, "si" }, // PANGO_SCRIPT_SINHALA
1910 { "x-central-euro", "sk" }, // PANGO_SCRIPT_LATIN
1911 { "x-central-euro", "sl" }, // PANGO_SCRIPT_LATIN
1912 { "x-western", "sm" },
1913 { "x-western", "sma" },
1914 { "x-western", "smj" },
1915 { "x-western", "smn" },
1916 { "x-western", "sms" },
1917 { "x-western", "so" },
1918 { "x-western", "sq" },
1919 { "x-cyrillic", "sr" },
1920 { "x-western", "sv" },
1921 { "x-western", "sw" },
1922 { 0, "syr" }, // PANGO_SCRIPT_SYRIAC
1923 { "x-tamil", "ta" },
1924 { 0, "te" }, // PANGO_SCRIPT_TELUGU
1925 { "x-cyrillic", "tg" },
1927 { "x-ethi", "ti-er" },
1928 { "x-ethi", "ti-et" },
1929 { "x-ethi", "tig" },
1930 { "x-cyrillic", "tk" },
1931 { 0, "tl" }, // PANGO_SCRIPT_TAGALOG
1932 { "x-western", "tn" },
1933 { "x-western", "to" },
1934 { "x-western", "tr" },
1935 { "x-western", "ts" },
1936 { "x-cyrillic", "tt" },
1937 { "x-western", "tw" },
1938 { "x-cyrillic", "tyv" },
1940 { "x-cyrillic", "uk" },
1942 { "x-cyrillic", "uz" },
1943 { "x-western", "ven" },
1944 { "x-western", "vi" },
1945 { "x-western", "vo" },
1946 { "x-western", "vot" },
1947 { "x-western", "wa" },
1948 { "x-western", "wen" },
1949 { "x-western", "wo" },
1950 { "x-western", "xh" },
1951 { "x-western", "yap" },
1953 { "x-western", "yo" },
1954 { "zh-CN", "zh-cn" },
1955 { "zh-HK", "zh-hk" },
1956 { "zh-HK", "zh-mo" },
1957 { "zh-CN", "zh-sg" },
1958 { "zh-TW", "zh-tw" },
1959 { "x-western", "zu" },
1962 #define NUM_PANGO_ALL_LANG_GROUPS (G_N_ELEMENTS (PangoAllLangGroup))
1964 gfxPangoFontCache::gfxPangoFontCache()
1966 mPangoFonts
.Init(500);
1969 gfxPangoFontCache::~gfxPangoFontCache()
1974 gfxPangoFontCache::Put(const PangoFontDescription
*aFontDesc
, PangoFont
*aPangoFont
)
1976 if (mPangoFonts
.Count() > 5000)
1977 mPangoFonts
.Clear();
1978 PRUint32 key
= pango_font_description_hash(aFontDesc
);
1979 gfxPangoFontWrapper
*value
= new gfxPangoFontWrapper(aPangoFont
);
1982 mPangoFonts
.Put(key
, value
);
1986 gfxPangoFontCache::Get(const PangoFontDescription
*aFontDesc
)
1988 PRUint32 key
= pango_font_description_hash(aFontDesc
);
1989 gfxPangoFontWrapper
*value
;
1990 if (!mPangoFonts
.Get(key
, &value
))
1992 PangoFont
*font
= value
->Get();