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 "nsMathUtils.h"
52 #include "nsServiceManagerUtils.h"
53 #include "nsILanguageAtomService.h"
55 #include "gfxContext.h"
56 #include "gfxPlatformGtk.h"
57 #include "gfxPangoFonts.h"
58 #include "gfxFontconfigUtils.h"
59 #include "gfxUserFontSet.h"
61 #include <freetype/tttables.h>
66 #include <fontconfig/fcfreetype.h>
67 #include <pango/pango.h>
68 #include <pango/pangofc-fontmap.h>
70 #ifdef MOZ_WIDGET_GTK2
71 #include <gdk/gdkscreen.h>
76 #define FLOAT_PANGO_SCALE ((gfxFloat)PANGO_SCALE)
78 #ifndef PANGO_VERSION_CHECK
79 #define PANGO_VERSION_CHECK(x,y,z) 0
81 #ifndef PANGO_GLYPH_UNKNOWN_FLAG
82 #define PANGO_GLYPH_UNKNOWN_FLAG ((PangoGlyph)0x10000000)
84 #ifndef PANGO_GLYPH_EMPTY
85 #define PANGO_GLYPH_EMPTY ((PangoGlyph)0)
87 // For g a PangoGlyph,
88 #define IS_MISSING_GLYPH(g) ((g) & PANGO_GLYPH_UNKNOWN_FLAG)
89 #define IS_EMPTY_GLYPH(g) ((g) == PANGO_GLYPH_EMPTY)
91 // Same as pango_units_from_double from Pango 1.16 (but not in older versions)
92 int moz_pango_units_from_double(double d
) {
93 return NS_lround(d
* FLOAT_PANGO_SCALE
);
96 static PangoLanguage
*GuessPangoLanguage(const nsACString
& aLangGroup
);
98 static cairo_scaled_font_t
*CreateScaledFont(FcPattern
*aPattern
);
100 static PangoFontMap
*gPangoFontMap
;
101 static PangoFontMap
*GetPangoFontMap();
103 static FT_Library gFTLibrary
;
104 static nsILanguageAtomService
* gLangService
;
106 NS_SPECIALIZE_TEMPLATE
107 class nsAutoRefTraits
<PangoFont
> : public gfxGObjectRefTraits
<PangoFont
> { };
109 NS_SPECIALIZE_TEMPLATE
110 class nsAutoRefTraits
<PangoCoverage
>
111 : public nsPointerRefTraits
<PangoCoverage
> {
113 static void Release(PangoCoverage
*aPtr
) { pango_coverage_unref(aPtr
); }
114 static void AddRef(PangoCoverage
*aPtr
) { pango_coverage_ref(aPtr
); }
118 // FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97
119 // and so fontconfig-2.3.0 (2005).
120 #ifndef FC_FAMILYLANG
121 #define FC_FAMILYLANG "familylang"
124 #define FC_FULLNAME "fullname"
127 // Rounding and truncation functions for a FreeType fixed point number
128 // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
129 // part and low 6 bits for the fractional part.
130 #define FLOAT_FROM_26_6(x) ((x) / 64.0)
131 #define FLOAT_FROM_16_16(x) ((x) / 65536.0)
132 #define ROUND_26_6_TO_INT(x) ((x) >= 0 ? ((32 + (x)) >> 6) \
133 : -((32 - (x)) >> 6))
134 // aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
135 static inline FT_Long
136 ScaleRoundDesignUnits(FT_Short aDesignMetric
, FT_Fixed aScale
)
138 FT_Long fixed26dot6
= FT_MulFix(aDesignMetric
, aScale
);
139 return ROUND_26_6_TO_INT(fixed26dot6
);
142 // A namespace for @font-face family names in FcPatterns so that fontconfig
143 // aliases do not pick up families from @font-face rules and so that
144 // fontconfig rules can distinguish between web fonts and platform fonts.
145 // http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
146 #define FONT_FACE_FAMILY_PREFIX "@font-face:"
151 * An abstract class for objects in a gfxUserFontSet that can provide an
152 * FcPattern* handle to a font face.
154 * Separate implementations of this class support local fonts from src:local()
155 * and web fonts from src:url().
158 class gfxFcFontEntry
: public gfxFontEntry
{
160 FcPattern
*GetPattern()
169 gfxFcFontEntry(const gfxProxyFontEntry
&aProxyEntry
)
170 // store the family name
171 : gfxFontEntry(aProxyEntry
.mFamily
->Name())
173 mItalic
= aProxyEntry
.mItalic
;
174 mWeight
= aProxyEntry
.mWeight
;
175 mStretch
= aProxyEntry
.mStretch
;
178 // Initializes mPattern.
179 virtual void InitPattern() = 0;
181 // Helper function to be called from InitPattern() to change the pattern
182 // so that it matches the CSS style descriptors and so gets properly
183 // sorted in font selection. This also avoids synthetic style effects
184 // being added by the renderer when the style of the font itself does not
185 // match the descriptor provided by the author.
186 void AdjustPatternToCSS();
188 nsCountedRef
<FcPattern
> mPattern
;
192 gfxFcFontEntry::AdjustPatternToCSS()
195 FcPatternGetInteger(mPattern
, FC_WEIGHT
, 0, &fontWeight
);
196 int cssWeight
= gfxFontconfigUtils::FcWeightForBaseWeight(mWeight
);
197 if (cssWeight
!= fontWeight
) {
198 FcPatternDel(mPattern
, FC_WEIGHT
);
199 FcPatternAddInteger(mPattern
, FC_WEIGHT
, cssWeight
);
203 FcResult res
= FcPatternGetInteger(mPattern
, FC_SLANT
, 0, &fontSlant
);
204 // gfxFontEntry doesn't understand the difference between oblique
206 if (res
!= FcResultMatch
||
207 IsItalic() != (fontSlant
!= FC_SLANT_ROMAN
)) {
208 FcPatternDel(mPattern
, FC_SLANT
);
209 FcPatternAddInteger(mPattern
, FC_SLANT
,
210 IsItalic() ? FC_SLANT_OBLIQUE
: FC_SLANT_ROMAN
);
213 // Ensure that there is a fullname property (if there is a family
214 // property) so that fontconfig rules can identify the real name of the
215 // font, because the family property will be replaced.
218 if (FcPatternGetString(mPattern
,
219 FC_FULLNAME
, 0, &fullname
) == FcResultNoMatch
&&
220 FcPatternGetString(mPattern
,
221 FC_FAMILY
, 0, &fontFamily
) == FcResultMatch
) {
222 // Construct fullname from family and style
223 nsCAutoString
fullname(gfxFontconfigUtils::ToCString(fontFamily
));
225 if (FcPatternGetString(mPattern
,
226 FC_STYLE
, 0, &fontStyle
) == FcResultMatch
) {
227 const char *style
= gfxFontconfigUtils::ToCString(fontStyle
);
228 if (strcmp(style
, "Regular") != 0) {
229 fullname
.Append(' ');
230 fullname
.Append(style
);
234 FcPatternAddString(mPattern
, FC_FULLNAME
,
235 gfxFontconfigUtils::ToFcChar8(fullname
.get()));
238 nsCAutoString family
;
239 family
.Append(FONT_FACE_FAMILY_PREFIX
);
240 AppendUTF16toUTF8(Name(), family
);
242 FcPatternDel(mPattern
, FC_FAMILY
);
243 FcPatternDel(mPattern
, FC_FAMILYLANG
);
244 FcPatternAddString(mPattern
, FC_FAMILY
,
245 gfxFontconfigUtils::ToFcChar8(family
.get()));
249 * gfxDownloadedFcFontEntry:
251 * An implementation of gfxFcFontEntry for web fonts from src:url().
254 class gfxDownloadedFcFontEntry
: public gfxFcFontEntry
{
256 // This takes ownership of the face.
257 gfxDownloadedFcFontEntry(const gfxProxyFontEntry
&aProxyEntry
,
258 nsISupports
*aLoader
, FT_Face aFace
)
259 : gfxFcFontEntry(aProxyEntry
), mLoader(aLoader
), mFace(aFace
)
261 NS_PRECONDITION(aFace
!= NULL
, "aFace is NULL!");
264 virtual ~gfxDownloadedFcFontEntry();
266 // Returns a PangoCoverage owned by the FontEntry. The caller must add a
267 // reference if it wishes to keep the PangoCoverage longer than the
268 // lifetime of the FontEntry.
269 PangoCoverage
*GetPangoCoverage();
272 virtual void InitPattern();
274 // mLoader holds a reference to memory used by mFace.
275 nsCOMPtr
<nsISupports
> mLoader
;
277 // mPangoCoverage is the charset property of mPattern translated to a
278 // format that Pango understands. A reference is kept here so that it can
279 // be shared by multiple PangoFonts (of different sizes).
280 nsAutoRef
<PangoCoverage
> mPangoCoverage
;
283 // A property for recording gfxDownloadedFcFontEntrys on FcPatterns.
284 static const char *kFontEntryFcProp
= "-moz-font-entry";
286 static FcBool
AddDownloadedFontEntry(FcPattern
*aPattern
,
287 gfxDownloadedFcFontEntry
*aFontEntry
)
290 value
.type
= FcTypeFTFace
; // void* field of union
291 value
.u
.f
= aFontEntry
;
293 return FcPatternAdd(aPattern
, kFontEntryFcProp
, value
, FcFalse
);
296 static FcBool
DelDownloadedFontEntry(FcPattern
*aPattern
)
298 return FcPatternDel(aPattern
, kFontEntryFcProp
);
301 static gfxDownloadedFcFontEntry
*GetDownloadedFontEntry(FcPattern
*aPattern
)
304 if (FcPatternGet(aPattern
, kFontEntryFcProp
, 0, &value
) != FcResultMatch
)
307 if (value
.type
!= FcTypeFTFace
) {
308 NS_NOTREACHED("Wrong type for -moz-font-entry font property");
312 return static_cast<gfxDownloadedFcFontEntry
*>(value
.u
.f
);
315 gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry()
318 // Remove back reference to this font entry and the face in case
319 // anyone holds a reference to the pattern.
320 DelDownloadedFontEntry(mPattern
);
321 FcPatternDel(mPattern
, FC_FT_FACE
);
326 typedef FcPattern
* (*QueryFaceFunction
)(const FT_Face face
,
327 const FcChar8
*file
, int id
,
330 static QueryFaceFunction
331 GetFcFreeTypeQueryFace()
333 PRLibrary
*lib
= nsnull
;
335 PR_FindFunctionSymbolAndLibrary("FcFreeTypeQueryFace", &lib
);
337 PR_UnloadLibrary(lib
);
340 return reinterpret_cast<QueryFaceFunction
>(result
);
344 gfxDownloadedFcFontEntry::InitPattern()
346 static QueryFaceFunction sQueryFacePtr
= GetFcFreeTypeQueryFace();
348 // FcFreeTypeQueryFace is the same function used to construct patterns for
349 // system fonts and so is the preferred function to use for this purpose.
350 // This will set up the langset property, which helps with sorting, and
351 // the foundry, fullname, and fontversion properties, which properly
352 // identify the font to fontconfig rules. However, FcFreeTypeQueryFace is
353 // available only from fontconfig-2.4.2 (December 2006). (CentOS 5.0 has
354 // fontconfig-2.4.1.)
356 // The "file" argument cannot be NULL (in fontconfig-2.6.0 at least).
357 // The dummy file passed here is removed below.
359 // When fontconfig scans the system fonts, FcConfigGetBlanks(NULL) is
360 // passed as the "blanks" argument, which provides that unexpectedly
361 // blank glyphs are elided. Here, however, we pass NULL for "blanks",
362 // effectively assuming that, if the font has a blank glyph, then the
363 // author intends any associated character to be rendered blank.
364 mPattern
.own((*sQueryFacePtr
)(mFace
,
365 gfxFontconfigUtils::ToFcChar8(""), 0,
368 // Either OOM, or fontconfig chose to skip this font because it
369 // has "no encoded characters", which I think means "BDF and PCF
370 // fonts which are not in Unicode (or the effectively equivalent
371 // ISO Latin-1) encoding".
374 // These properties don't make sense for this face without a file.
375 FcPatternDel(mPattern
, FC_FILE
);
376 FcPatternDel(mPattern
, FC_INDEX
);
379 // Do the minimum necessary to construct a pattern for sorting.
381 // FC_CHARSET is vital to determine which characters are supported.
382 nsAutoRef
<FcCharSet
> charset(FcFreeTypeCharSet(mFace
, NULL
));
383 // If there are no characters then assume we don't know how to read
384 // this font and leave mPattern NULL.
385 if (!charset
|| FcCharSetCount(charset
) == 0)
388 mPattern
.own(FcPatternCreate());
389 FcPatternAddCharSet(mPattern
, FC_CHARSET
, charset
);
391 // FC_PIXEL_SIZE can be important for font selection of fixed-size
393 if (!(mFace
->face_flags
& FT_FACE_FLAG_SCALABLE
)) {
394 for (FT_Int i
= 0; i
< mFace
->num_fixed_sizes
; ++i
) {
395 #if HAVE_FT_BITMAP_SIZE_Y_PPEM
396 double size
= FLOAT_FROM_26_6(mFace
->available_sizes
[i
].y_ppem
);
398 double size
= mFace
->available_sizes
[i
].height
;
400 FcPatternAddDouble (mPattern
, FC_PIXEL_SIZE
, size
);
403 // Not sure whether this is important;
404 // imitating FcFreeTypeQueryFace:
405 FcPatternAddBool (mPattern
, FC_ANTIALIAS
, FcFalse
);
408 // Setting up the FC_LANGSET property is very difficult with the APIs
409 // available prior to FcFreeTypeQueryFace. Having no FC_LANGSET
410 // property seems better than having a property with an empty LangSet.
411 // With no FC_LANGSET property, fontconfig sort functions will
412 // consider this face to have the same priority as (otherwise equal)
413 // faces that have support for the primary requested language, but
414 // will not consider any language to have been satisfied (and so will
415 // continue to look for a face with language support in fallback
419 FcPatternAddFTFace(mPattern
, FC_FT_FACE
, mFace
);
420 AddDownloadedFontEntry(mPattern
, this);
422 AdjustPatternToCSS();
425 static PangoCoverage
*NewPangoCoverage(FcPattern
*aFont
)
427 // This uses g_slice_alloc which will abort on OOM rather than return NULL.
428 PangoCoverage
*coverage
= pango_coverage_new();
431 if (FcPatternGetCharSet(aFont
, FC_CHARSET
, 0, &charset
) != FcResultMatch
)
432 return coverage
; // empty
435 FcChar32 map
[FC_CHARSET_MAP_SIZE
];
437 for (base
= FcCharSetFirstPage(charset
, map
, &next
);
438 base
!= FC_CHARSET_DONE
;
439 base
= FcCharSetNextPage(charset
, map
, &next
)) {
440 for (PRUint32 i
= 0; i
< FC_CHARSET_MAP_SIZE
; ++i
) {
442 FcChar32 bitmap
= map
[i
];
443 for (; bitmap
; bitmap
>>= 1) {
445 pango_coverage_set(coverage
, base
+ offset
,
446 PANGO_COVERAGE_EXACT
);
457 gfxDownloadedFcFontEntry::GetPangoCoverage()
459 if (!mPangoCoverage
) {
460 mPangoCoverage
.own(NewPangoCoverage(mPattern
));
462 return mPangoCoverage
;
468 * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
469 * cairo_scaled_font created from an FcPattern.
472 class gfxFcFont
: public gfxFont
{
474 virtual ~gfxFcFont ();
475 static already_AddRefed
<gfxFcFont
> GetOrMakeFont(FcPattern
*aPattern
);
477 virtual const gfxFont::Metrics
& GetMetrics();
479 virtual nsString
GetUniqueName();
481 // Get the glyphID of a space
482 virtual PRUint32
GetSpaceGlyph() {
483 NS_ASSERTION(GetStyle()->size
!= 0,
484 "forgot to short-circuit a text run with zero-sized font?");
489 cairo_scaled_font_t
*CairoScaledFont() { return mCairoFont
; }
490 void GetGlyphExtents(PRUint32 aGlyph
, cairo_text_extents_t
* aExtents
);
493 cairo_scaled_font_t
*mCairoFont
;
495 PRUint32 mSpaceGlyph
;
497 PRPackedBool mHasMetrics
;
499 gfxFcFont(cairo_scaled_font_t
*aCairoFont
,
500 gfxFontEntry
*aFontEntry
, const gfxFontStyle
*aFontStyle
);
502 virtual PRBool
SetupCairoFont(gfxContext
*aContext
);
504 // key for locating a gfxFcFont corresponding to a cairo_scaled_font
505 static cairo_user_data_key_t sGfxFontKey
;
510 LockedFTFace(gfxFcFont
*aFont
)
512 mFace(cairo_ft_scaled_font_lock_face(aFont
->CairoScaledFont()))
519 cairo_ft_scaled_font_unlock_face(mGfxFont
->CairoScaledFont());
529 * Get extents for a simple character representable by a single glyph.
530 * The return value is the glyph id of that glyph or zero if no such glyph
531 * exists. aExtents is only set when this returns a non-zero glyph id.
533 PRUint32
GetCharExtents(char aChar
, cairo_text_extents_t
* aExtents
);
535 void GetMetrics(gfxFont::Metrics
* aMetrics
, PRUint32
* aSpaceGlyph
);
538 nsRefPtr
<gfxFcFont
> mGfxFont
;
545 * An implementation of PangoFcFont that wraps a gfxFont so that it can be
546 * passed to PangoRenderFc shapers.
548 * Many of these will be created for pango_itemize, but most will only be
549 * tested for coverage of individual characters (and sometimes not even that).
550 * Therefore the gfxFont is only constructed if and when needed.
553 #define GFX_TYPE_PANGO_FC_FONT (gfx_pango_fc_font_get_type())
554 #define GFX_PANGO_FC_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFont))
555 #define GFX_IS_PANGO_FC_FONT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FC_FONT))
558 GType
gfx_pango_fc_font_get_type (void);
560 #define GFX_PANGO_FC_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFontClass))
561 #define GFX_IS_PANGO_FC_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FC_FONT))
562 #define GFX_PANGO_FC_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FC_FONT, gfxPangoFcFontClass))
564 // This struct is POD so that it can be used as a GObject.
565 struct gfxPangoFcFont
{
566 PangoFcFont parent_instance
;
568 FcPattern
*mRequestedPattern
;
569 PangoCoverage
*mCoverage
;
572 static nsReturnRef
<PangoFont
>
573 NewFont(FcPattern
*aRequestedPattern
, FcPattern
*aFontPattern
)
575 // A pattern is needed for pango_fc_font_finalize.
577 // Adding a ref to the requested pattern and one of fontconfig's
578 // patterns uses much less memory than using the fully resolved
579 // pattern here, and saves calling FcFontRenderPrepare when the
580 // PangoFont is only tested for character coverage.
582 // Normally the is_hinted field of the PangoFcFont is set based on the
583 // FC_HINTING property on the pattern at construction, but this
584 // property is not known until after RenderPrepare. is_hinted is used
585 // by pango_fc_font_kern_glyphs, which is sometimes used by
586 // pango_ot_buffer_output. is_hinted will be set when the gfxFont is
587 // constructed for PangoFcFont::lock_face.
588 gfxPangoFcFont
*font
= static_cast<gfxPangoFcFont
*>
589 (g_object_new(GFX_TYPE_PANGO_FC_FONT
,
590 "pattern", aFontPattern
, NULL
));
592 // Save the requested pattern for FcFontRenderPrepare.
593 FcPatternReference(aRequestedPattern
);
594 font
->mRequestedPattern
= aRequestedPattern
;
596 // PangoFcFont::get_coverage wants an FcFontMap. (PangoFcFontMap
597 // usually sets this after calling PangoFcFontMap::create_font().)
598 PangoFcFont
*fc_font
= &font
->parent_instance
;
599 fc_font
->fontmap
= GetPangoFontMap();
600 g_object_ref(fc_font
->fontmap
);
602 return nsReturnRef
<PangoFont
>(PANGO_FONT(font
));
605 static gfxFcFont
*GfxFont(gfxPangoFcFont
*self
)
607 if (!self
->mGfxFont
) {
608 PangoFcFont
*fc_font
= &self
->parent_instance
;
610 if (NS_LIKELY(self
->mRequestedPattern
)) {
611 // Created with gfxPangoFcFont::NewFont()
612 nsAutoRef
<FcPattern
> renderPattern
613 (FcFontRenderPrepare(NULL
, self
->mRequestedPattern
,
614 fc_font
->font_pattern
));
618 FcBool hinting
= FcTrue
;
619 FcPatternGetBool(renderPattern
, FC_HINTING
, 0, &hinting
);
620 fc_font
->is_hinted
= hinting
;
622 // is_transformed does not appear to be used anywhere but looks
623 // like it should be set.
625 FcResult result
= FcPatternGetMatrix(renderPattern
,
626 FC_MATRIX
, 0, &matrix
);
627 fc_font
->is_transformed
=
628 result
== FcResultMatch
&&
629 (matrix
->xy
!= 0.0 || matrix
->yx
!= 0.0 ||
630 matrix
->xx
!= 1.0 || matrix
->yy
!= 1.0);
632 self
->mGfxFont
= gfxFcFont::GetOrMakeFont(renderPattern
).get();
633 if (self
->mGfxFont
) {
634 // Finished with the requested pattern
635 FcPatternDestroy(self
->mRequestedPattern
);
636 self
->mRequestedPattern
= NULL
;
640 // Created with gfxPangoFontMap::create_font()
642 gfxFcFont::GetOrMakeFont(fc_font
->font_pattern
).get();
645 return self
->mGfxFont
;
648 static cairo_scaled_font_t
*CairoFont(gfxPangoFcFont
*self
)
650 return gfxPangoFcFont::GfxFont(self
)->CairoScaledFont();
654 struct gfxPangoFcFontClass
{
655 PangoFcFontClass parent_class
;
658 G_DEFINE_TYPE (gfxPangoFcFont
, gfx_pango_fc_font
, PANGO_TYPE_FC_FONT
)
661 gfx_pango_fc_font_init(gfxPangoFcFont
*font
)
667 gfx_pango_fc_font_finalize(GObject
*object
)
669 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(object
);
671 if (self
->mRequestedPattern
)
672 FcPatternDestroy(self
->mRequestedPattern
);
674 pango_coverage_unref(self
->mCoverage
);
675 NS_IF_RELEASE(self
->mGfxFont
);
677 // The parent class removes the reference to parent_instance->fontmap.
679 G_OBJECT_CLASS(gfx_pango_fc_font_parent_class
)->finalize(object
);
682 static PangoCoverage
*
683 gfx_pango_fc_font_get_coverage(PangoFont
*font
, PangoLanguage
*lang
)
685 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(font
);
687 // The coverage is requested often enough that it is worth holding a
688 // reference on the font.
689 if (!self
->mCoverage
) {
690 FcPattern
*pattern
= self
->parent_instance
.font_pattern
;
691 gfxDownloadedFcFontEntry
*downloadedFontEntry
=
692 GetDownloadedFontEntry(pattern
);
693 // The parent class implementation requires the font pattern to have
694 // a file and caches results against that filename. This is not
695 // suitable for web fonts.
696 if (!downloadedFontEntry
) {
698 PANGO_FONT_CLASS(gfx_pango_fc_font_parent_class
)->
699 get_coverage(font
, lang
);
702 pango_coverage_ref(downloadedFontEntry
->GetPangoCoverage());
706 return pango_coverage_ref(self
->mCoverage
);
709 static PangoFontDescription
*
710 gfx_pango_fc_font_describe(PangoFont
*font
)
712 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(font
);
713 PangoFcFont
*fcFont
= &self
->parent_instance
;
714 PangoFontDescription
*result
=
715 pango_font_description_copy(fcFont
->description
);
717 gfxFcFont
*gfxFont
= gfxPangoFcFont::GfxFont(self
);
719 double pixelsize
= gfxFont
->GetStyle()->size
;
720 double dpi
= gfxPlatformGtk::DPI();
721 gint size
= moz_pango_units_from_double(pixelsize
* dpi
/ 72.0);
722 pango_font_description_set_size(result
, size
);
727 static PangoFontDescription
*
728 gfx_pango_fc_font_describe_absolute(PangoFont
*font
)
730 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(font
);
731 PangoFcFont
*fcFont
= &self
->parent_instance
;
732 PangoFontDescription
*result
=
733 pango_font_description_copy(fcFont
->description
);
735 gfxFcFont
*gfxFont
= gfxPangoFcFont::GfxFont(self
);
737 double size
= gfxFont
->GetStyle()->size
* PANGO_SCALE
;
738 pango_font_description_set_absolute_size(result
, size
);
744 gfx_pango_fc_font_get_glyph_extents(PangoFont
*font
, PangoGlyph glyph
,
745 PangoRectangle
*ink_rect
,
746 PangoRectangle
*logical_rect
)
748 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(font
);
749 gfxFcFont
*gfxFont
= gfxPangoFcFont::GfxFont(self
);
751 if (IS_MISSING_GLYPH(glyph
)) {
752 const gfxFont::Metrics
& metrics
= gfxFont
->GetMetrics();
756 rect
.y
= moz_pango_units_from_double(-metrics
.maxAscent
);
757 rect
.width
= moz_pango_units_from_double(metrics
.aveCharWidth
);
758 rect
.height
= moz_pango_units_from_double(metrics
.maxHeight
);
763 *logical_rect
= rect
;
769 // logical_rect.width is possibly used by pango_ot_buffer_output (used
770 // by many shapers) and used by fallback_engine_shape (possibly used
771 // by pango_shape and pango_itemize when no glyphs are found). I
772 // doubt the other fields will be used but we won't have any way to
773 // detecting if they are so we'd better set them.
774 const gfxFont::Metrics
& metrics
= gfxFont
->GetMetrics();
775 logical_rect
->y
= moz_pango_units_from_double(-metrics
.maxAscent
);
776 logical_rect
->height
= moz_pango_units_from_double(metrics
.maxHeight
);
779 cairo_text_extents_t extents
;
780 if (IS_EMPTY_GLYPH(glyph
)) {
781 new (&extents
) cairo_text_extents_t(); // zero
783 gfxFont
->GetGlyphExtents(glyph
, &extents
);
787 ink_rect
->x
= moz_pango_units_from_double(extents
.x_bearing
);
788 ink_rect
->y
= moz_pango_units_from_double(extents
.y_bearing
);
789 ink_rect
->width
= moz_pango_units_from_double(extents
.width
);
790 ink_rect
->height
= moz_pango_units_from_double(extents
.height
);
794 logical_rect
->width
= moz_pango_units_from_double(extents
.x_advance
);
798 static PangoFontMetrics
*
799 gfx_pango_fc_font_get_metrics(PangoFont
*font
, PangoLanguage
*language
)
801 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(font
);
803 // This uses g_slice_alloc which will abort on OOM rather than return NULL.
804 PangoFontMetrics
*result
= pango_font_metrics_new();
806 gfxFcFont
*gfxFont
= gfxPangoFcFont::GfxFont(self
);
808 const gfxFont::Metrics
& metrics
= gfxFont
->GetMetrics();
810 result
->ascent
= moz_pango_units_from_double(metrics
.maxAscent
);
811 result
->descent
= moz_pango_units_from_double(metrics
.maxDescent
);
812 result
->approximate_char_width
=
813 moz_pango_units_from_double(metrics
.aveCharWidth
);
814 result
->approximate_digit_width
=
815 moz_pango_units_from_double(metrics
.zeroOrAveCharWidth
);
816 result
->underline_position
=
817 moz_pango_units_from_double(metrics
.underlineOffset
);
818 result
->underline_thickness
=
819 moz_pango_units_from_double(metrics
.underlineSize
);
820 result
->strikethrough_position
=
821 moz_pango_units_from_double(metrics
.strikeoutOffset
);
822 result
->strikethrough_thickness
=
823 moz_pango_units_from_double(metrics
.strikeoutSize
);
829 gfx_pango_fc_font_lock_face(PangoFcFont
*font
)
831 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(font
);
832 return cairo_ft_scaled_font_lock_face(gfxPangoFcFont::CairoFont(self
));
836 gfx_pango_fc_font_unlock_face(PangoFcFont
*font
)
838 gfxPangoFcFont
*self
= GFX_PANGO_FC_FONT(font
);
839 cairo_ft_scaled_font_unlock_face(gfxPangoFcFont::CairoFont(self
));
843 gfx_pango_fc_font_class_init (gfxPangoFcFontClass
*klass
)
845 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
846 PangoFontClass
*font_class
= PANGO_FONT_CLASS (klass
);
847 PangoFcFontClass
*fc_font_class
= PANGO_FC_FONT_CLASS (klass
);
849 object_class
->finalize
= gfx_pango_fc_font_finalize
;
851 font_class
->get_coverage
= gfx_pango_fc_font_get_coverage
;
852 // describe is called on errors in pango_shape.
853 font_class
->describe
= gfx_pango_fc_font_describe
;
854 font_class
->get_glyph_extents
= gfx_pango_fc_font_get_glyph_extents
;
855 // get_metrics and describe_absolute are not likely to be used but
856 // implemented because the class makes them available.
857 font_class
->get_metrics
= gfx_pango_fc_font_get_metrics
;
858 font_class
->describe_absolute
= gfx_pango_fc_font_describe_absolute
;
859 // font_class->find_shaper,get_font_map are inherited from PangoFcFontClass
861 // fc_font_class->has_char,get_glyph are inherited
862 fc_font_class
->lock_face
= gfx_pango_fc_font_lock_face
;
863 fc_font_class
->unlock_face
= gfx_pango_fc_font_unlock_face
;
867 * Recording a gfxPangoFontGroup on a PangoContext
870 static GQuark
GetFontGroupQuark()
872 // Not using g_quark_from_static_string() because this module may be
873 // unloaded (which would leave a dangling pointer). Using
874 // g_quark_from_string() instead, which creates a small shutdown leak.
875 static GQuark quark
= g_quark_from_string("moz-font-group");
880 gfxFontGroup_unref(gpointer data
)
882 gfxPangoFontGroup
*fontGroup
= static_cast<gfxPangoFontGroup
*>(data
);
883 NS_RELEASE(fontGroup
);
887 SetFontGroup(PangoContext
*aContext
, gfxPangoFontGroup
*aFontGroup
)
889 NS_ADDREF(aFontGroup
);
890 g_object_set_qdata_full(G_OBJECT(aContext
), GetFontGroupQuark(),
891 aFontGroup
, gfxFontGroup_unref
);
894 static gfxPangoFontGroup
*
895 GetFontGroup(PangoContext
*aContext
)
897 return static_cast<gfxPangoFontGroup
*>
898 (g_object_get_qdata(G_OBJECT(aContext
), GetFontGroupQuark()));
904 * Translation from a desired FcPattern to a sorted set of font references
905 * (fontconfig cache data) and (when needed) PangoFonts.
908 class gfxFcPangoFontSet
{
910 THEBES_INLINE_DECL_REFCOUNTING(gfxFcPangoFontSet
)
912 explicit gfxFcPangoFontSet(FcPattern
*aPattern
,
913 gfxUserFontSet
*aUserFontSet
)
914 : mSortPattern(aPattern
), mUserFontSet(aUserFontSet
),
915 mFcFontSet(SortPreferredFonts()), mFcFontsTrimmed(0),
916 mHaveFallbackFonts(PR_FALSE
)
920 // A reference is held by the FontSet.
921 // The caller may add a ref to keep the font alive longer than the FontSet.
922 PangoFont
*GetFontAt(PRUint32 i
)
924 if (i
>= mFonts
.Length() || !mFonts
[i
].mFont
) {
925 // GetFontPatternAt sets up mFonts
926 FcPattern
*fontPattern
= GetFontPatternAt(i
);
931 gfxPangoFcFont::NewFont(mSortPattern
, fontPattern
);
933 return mFonts
[i
].mFont
;
936 FcPattern
*GetFontPatternAt(PRUint32 i
);
939 nsReturnRef
<FcFontSet
> SortPreferredFonts();
940 nsReturnRef
<FcFontSet
> SortFallbackFonts();
943 explicit FontEntry(FcPattern
*aPattern
) : mPattern(aPattern
) {}
944 nsCountedRef
<FcPattern
> mPattern
;
945 nsCountedRef
<PangoFont
> mFont
;
948 struct LangSupportEntry
{
949 LangSupportEntry(FcChar8
*aLang
, FcLangResult aSupport
) :
950 mLang(aLang
), mBestSupport(aSupport
) {}
952 FcLangResult mBestSupport
;
956 // public for nsTArray
957 class LangComparator
{
959 PRBool
Equals(const LangSupportEntry
& a
, const FcChar8
*b
) const
961 return FcStrCmpIgnoreCase(a
.mLang
, b
) == 0;
966 // The requested pattern
967 nsCountedRef
<FcPattern
> mSortPattern
;
968 // Fonts from @font-face rules
969 nsRefPtr
<gfxUserFontSet
> mUserFontSet
;
970 // A (trimmed) list of font patterns and PangoFonts that is built up as
972 nsTArray
<FontEntry
> mFonts
;
973 // Holds a list of font patterns that will be trimmed. This is first set
974 // to a list of preferred fonts. Then, if/when all the preferred fonts
975 // have been trimmed and added to mFonts, this is set to a list of
977 nsAutoRef
<FcFontSet
> mFcFontSet
;
978 // The set of characters supported by the fonts in mFonts.
979 nsAutoRef
<FcCharSet
> mCharSet
;
980 // The index of the next font in mFcFontSet that has not yet been
981 // considered for mFonts.
983 // True iff fallback fonts are either stored in mFcFontSet or have been
984 // trimmed and added to mFonts (so that mFcFontSet is NULL).
985 PRPackedBool mHaveFallbackFonts
;
988 // Find the FcPattern for an @font-face font suitable for CSS family |aFamily|
989 // and style |aStyle| properties.
991 FindFontPattern(gfxUserFontSet
*mUserFontSet
,
992 const nsACString
&aFamily
, PRUint8 aStyle
, PRUint16 aWeight
)
995 NS_ConvertUTF8toUTF16
utf16Family(aFamily
);
997 // needsBold is not used here. Instead synthetic bold is enabled through
998 // FcFontRenderPrepare when the weight in the requested pattern is
999 // compared against the weight in the font pattern.
1003 style
.style
= aStyle
;
1004 style
.weight
= aWeight
;
1006 gfxFcFontEntry
*fontEntry
= static_cast<gfxFcFontEntry
*>
1007 (mUserFontSet
->FindFontEntry(utf16Family
, style
, needsBold
));
1009 // Accept synthetic oblique for italic and oblique.
1010 if (!fontEntry
&& aStyle
!= FONT_STYLE_NORMAL
) {
1011 style
.style
= FONT_STYLE_NORMAL
;
1012 fontEntry
= static_cast<gfxFcFontEntry
*>
1013 (mUserFontSet
->FindFontEntry(utf16Family
, style
, needsBold
));
1019 return fontEntry
->GetPattern();
1022 typedef FcBool (*FcPatternRemoveFunction
)(FcPattern
*p
, const char *object
,
1025 static FcPatternRemoveFunction
1026 GetFcPatternRemove()
1028 PRLibrary
*lib
= nsnull
;
1030 PR_FindFunctionSymbolAndLibrary("FcPatternRemove", &lib
);
1032 PR_UnloadLibrary(lib
);
1035 return reinterpret_cast<FcPatternRemoveFunction
>(result
);
1038 // FcPatternRemove is available in fontconfig-2.3.0 (2005)
1040 moz_FcPatternRemove(FcPattern
*p
, const char *object
, int id
)
1042 static FcPatternRemoveFunction sFcPatternRemovePtr
= GetFcPatternRemove();
1044 if (!sFcPatternRemovePtr
)
1047 return (*sFcPatternRemovePtr
)(p
, object
, id
);
1050 // fontconfig always prefers a matching family to a matching slant, but CSS
1051 // mostly prioritizes slant. The logic here is from CSS 2.1.
1053 SlantIsAcceptable(FcPattern
*aFont
, int aRequestedSlant
)
1055 // CSS accepts (possibly synthetic) oblique for italic.
1056 if (aRequestedSlant
== FC_SLANT_ITALIC
)
1060 FcResult result
= FcPatternGetInteger(aFont
, FC_SLANT
, 0, &slant
);
1061 // Not having a value would be strange.
1062 // fontconfig sort and match functions would consider no value a match.
1063 if (result
!= FcResultMatch
)
1066 switch (aRequestedSlant
) {
1067 case FC_SLANT_ROMAN
:
1068 // CSS requires an exact match
1069 return slant
== aRequestedSlant
;
1070 case FC_SLANT_OBLIQUE
:
1071 // Accept synthetic oblique from Roman,
1072 // but CSS doesn't accept italic.
1073 return slant
!= FC_SLANT_ITALIC
;
1079 // fontconfig prefers a matching family or lang to pixelsize of bitmap
1080 // fonts. CSS suggests a tolerance of 20% on pixelsize.
1082 SizeIsAcceptable(FcPattern
*aFont
, double aRequestedSize
)
1086 while (FcPatternGetDouble(aFont
,
1087 FC_PIXEL_SIZE
, v
, &size
) == FcResultMatch
) {
1089 if (5.0 * fabs(size
- aRequestedSize
) < aRequestedSize
)
1093 // No size means scalable
1097 // Sorting only the preferred fonts first usually saves having to sort through
1098 // every font on the system.
1099 nsReturnRef
<FcFontSet
>
1100 gfxFcPangoFontSet::SortPreferredFonts()
1102 gfxFontconfigUtils
*utils
= gfxFontconfigUtils::GetFontconfigUtils();
1104 return nsReturnRef
<FcFontSet
>();
1106 // The list of families in mSortPattern has values with both weak and
1107 // strong bindings. Values with strong bindings should be preferred.
1108 // Values with weak bindings are default fonts that should be considered
1109 // only when the font provides the best support for a requested language
1110 // or after other fonts have satisfied all the requested languages.
1112 // There are no direct fontconfig APIs to get the binding type. The
1113 // binding only takes effect in the sort and match functions.
1115 // |requiredLangs| is a list of requested languages that have not yet been
1116 // satisfied. gfxFontconfigUtils only sets one FC_LANG property value,
1117 // but FcConfigSubstitute may add more values (e.g. prepending "en" to
1118 // "ja" will use western fonts to render Latin/Arabic numerals in Japanese
1120 nsAutoTArray
<LangSupportEntry
,10> requiredLangs
;
1121 for (int v
= 0; ; ++v
) {
1123 FcResult result
= FcPatternGetString(mSortPattern
, FC_LANG
, v
, &lang
);
1124 if (result
!= FcResultMatch
) {
1125 // No need to check FcPatternGetLangSet() because
1126 // gfxFontconfigUtils sets only a string value for FC_LANG and
1127 // FcConfigSubstitute cannot add LangSets.
1128 NS_ASSERTION(result
!= FcResultTypeMismatch
,
1129 "Expected a string for FC_LANG");
1133 if (!requiredLangs
.Contains(lang
, LangComparator())) {
1134 FcLangResult bestLangSupport
= utils
->GetBestLangSupport(lang
);
1135 if (bestLangSupport
!= FcLangDifferentLang
) {
1137 AppendElement(LangSupportEntry(lang
, bestLangSupport
));
1142 nsAutoRef
<FcFontSet
> fontSet(FcFontSetCreate());
1144 return fontSet
.out();
1146 // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever
1147 // doesn't happen, Roman will be used.
1148 int requestedSlant
= FC_SLANT_ROMAN
;
1149 FcPatternGetInteger(mSortPattern
, FC_SLANT
, 0, &requestedSlant
);
1150 double requestedSize
= -1.0;
1151 FcPatternGetDouble(mSortPattern
, FC_PIXEL_SIZE
, 0, &requestedSize
);
1153 nsTHashtable
<gfxFontconfigUtils::DepFcStrEntry
> existingFamilies
;
1154 existingFamilies
.Init(50);
1157 FcPatternGetString(mSortPattern
,
1158 FC_FAMILY
, v
, &family
) == FcResultMatch
; ++v
) {
1159 nsAutoTArray
<nsCountedRef
<FcPattern
>,1> userFont
;
1160 const nsTArray
< nsCountedRef
<FcPattern
> > *familyFonts
= nsnull
;
1163 // Have some @font-face definitions
1165 nsDependentCString
cFamily(gfxFontconfigUtils::ToCString(family
));
1166 NS_NAMED_LITERAL_CSTRING(userPrefix
, FONT_FACE_FAMILY_PREFIX
);
1168 if (StringBeginsWith(cFamily
, userPrefix
)) {
1169 // This is an @font-face family.
1170 familyFonts
= &userFont
;
1172 // Trim off the prefix
1173 nsDependentCSubstring
cssFamily(cFamily
, userPrefix
.Length());
1175 PRUint8 thebesStyle
=
1176 gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant
);
1177 PRUint16 thebesWeight
=
1178 gfxFontconfigUtils::GetThebesWeight(mSortPattern
);
1180 FcPattern
*fontPattern
=
1181 FindFontPattern(mUserFontSet
, cssFamily
,
1182 thebesStyle
, thebesWeight
);
1185 userFont
.AppendElement(fontPattern
);
1191 familyFonts
= &utils
->GetFontsForFamily(family
);
1194 if (familyFonts
->Length() == 0) {
1195 // There are no fonts matching this family, so there is not point
1196 // in searching for this family in the FontSort.
1198 // Perhaps the original pattern should be retained for
1199 // FcFontRenderPrepare. However, the only a useful config
1200 // substitution test against missing families that i can imagine
1201 // would only be interested in the preferred family
1202 // (qual="first"), so always keep the first family and use the
1203 // same pattern for Sort and RenderPrepare.
1204 if (v
!= 0 && moz_FcPatternRemove(mSortPattern
, FC_FAMILY
, v
)) {
1210 // Aliases seem to often end up occurring more than once, but
1211 // duplicate families can't be removed from the sort pattern without
1212 // knowing whether duplicates have the same binding.
1213 gfxFontconfigUtils::DepFcStrEntry
*entry
=
1214 existingFamilies
.PutEntry(family
);
1216 if (entry
->mKey
) // old entry
1219 entry
->mKey
= family
; // initialize new entry
1222 for (PRUint32 f
= 0; f
< familyFonts
->Length(); ++f
) {
1223 FcPattern
*font
= familyFonts
->ElementAt(f
);
1225 // User fonts are already filtered by slant (but not size) in
1226 // mUserFontSet->FindFontEntry().
1227 if (familyFonts
!= &userFont
&&
1228 !SlantIsAcceptable(font
, requestedSlant
))
1230 if (requestedSize
!= -1.0 && !SizeIsAcceptable(font
, requestedSize
))
1233 for (PRUint32 r
= 0; r
< requiredLangs
.Length(); ++r
) {
1234 const LangSupportEntry
& entry
= requiredLangs
[r
];
1235 FcLangResult support
=
1236 gfxFontconfigUtils::GetLangSupport(font
, entry
.mLang
);
1237 if (support
<= entry
.mBestSupport
) { // lower is better
1238 requiredLangs
.RemoveElementAt(r
);
1243 // FcFontSetDestroy will remove a reference but FcFontSetAdd
1244 // does _not_ take a reference!
1245 if (FcFontSetAdd(fontSet
, font
)) {
1246 FcPatternReference(font
);
1251 FcPattern
*truncateMarker
= NULL
;
1252 for (PRUint32 r
= 0; r
< requiredLangs
.Length(); ++r
) {
1253 const nsTArray
< nsCountedRef
<FcPattern
> >& langFonts
=
1254 utils
->GetFontsForLang(requiredLangs
[r
].mLang
);
1256 PRBool haveLangFont
= PR_FALSE
;
1257 for (PRUint32 f
= 0; f
< langFonts
.Length(); ++f
) {
1258 FcPattern
*font
= langFonts
[f
];
1259 if (!SlantIsAcceptable(font
, requestedSlant
))
1261 if (requestedSize
!= -1.0 && !SizeIsAcceptable(font
, requestedSize
))
1264 haveLangFont
= PR_TRUE
;
1265 if (FcFontSetAdd(fontSet
, font
)) {
1266 FcPatternReference(font
);
1270 if (!haveLangFont
&& langFonts
.Length() > 0) {
1271 // There is a font that supports this language but it didn't pass
1272 // the slant and size criteria. Weak default font families should
1273 // not be considered until the language has been satisfied.
1275 // Insert a font that supports the language so that it will mark
1276 // the position of fonts from weak families in the sorted set and
1277 // they can be removed. The language and weak families will be
1278 // considered in the fallback fonts, which use fontconfig's
1281 // Of the fonts that don't meet slant and size criteria, strong
1282 // default font families should be considered before (other) fonts
1283 // for this language, so this marker font will be removed (as well
1284 // as the fonts from weak families), and strong families will be
1285 // reconsidered in the fallback fonts.
1286 FcPattern
*font
= langFonts
[0];
1287 if (FcFontSetAdd(fontSet
, font
)) {
1288 FcPatternReference(font
);
1289 truncateMarker
= font
;
1295 FcFontSet
*sets
[1] = { fontSet
};
1297 fontSet
.own(FcFontSetSort(NULL
, sets
, 1, mSortPattern
,
1298 FcFalse
, NULL
, &result
));
1300 if (truncateMarker
!= NULL
&& fontSet
) {
1301 nsAutoRef
<FcFontSet
> truncatedSet(FcFontSetCreate());
1303 for (int f
= 0; f
< fontSet
->nfont
; ++f
) {
1304 FcPattern
*font
= fontSet
->fonts
[f
];
1305 if (font
== truncateMarker
)
1308 if (FcFontSetAdd(truncatedSet
, font
)) {
1309 FcPatternReference(font
);
1313 fontSet
.steal(truncatedSet
);
1316 return fontSet
.out();
1319 nsReturnRef
<FcFontSet
>
1320 gfxFcPangoFontSet::SortFallbackFonts()
1322 // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet,
1323 // but would take much longer due to comparing all the character sets.
1325 // The references to fonts in this FcFontSet are almost free
1326 // as they are pointers into mmaped cache files.
1328 // GetFontPatternAt() will trim lazily if and as needed, which will also
1329 // remove duplicates of preferred fonts.
1331 return nsReturnRef
<FcFontSet
>(FcFontSort(NULL
, mSortPattern
,
1332 FcFalse
, NULL
, &result
));
1335 // GetFontAt relies on this setting up all patterns up to |i|.
1337 gfxFcPangoFontSet::GetFontPatternAt(PRUint32 i
)
1339 while (i
>= mFonts
.Length()) {
1340 while (!mFcFontSet
) {
1341 if (mHaveFallbackFonts
)
1344 mFcFontSet
= SortFallbackFonts();
1345 mHaveFallbackFonts
= PR_TRUE
;
1346 mFcFontsTrimmed
= 0;
1347 // Loop to test that mFcFontSet is non-NULL.
1350 while (mFcFontsTrimmed
< mFcFontSet
->nfont
) {
1351 FcPattern
*font
= mFcFontSet
->fonts
[mFcFontsTrimmed
];
1354 if (mFonts
.Length() != 0) {
1355 // See if the next font provides support for any extra
1356 // characters. Most often the next font is not going to
1357 // support more characters so check for a SubSet first before
1358 // allocating a new CharSet with Union.
1359 FcCharSet
*supportedChars
= mCharSet
;
1360 if (!supportedChars
) {
1361 FcPatternGetCharSet(mFonts
[mFonts
.Length() - 1].mPattern
,
1362 FC_CHARSET
, 0, &supportedChars
);
1365 if (supportedChars
) {
1366 FcCharSet
*newChars
= NULL
;
1367 FcPatternGetCharSet(font
, FC_CHARSET
, 0, &newChars
);
1369 if (FcCharSetIsSubset(newChars
, supportedChars
))
1372 mCharSet
.own(FcCharSetUnion(supportedChars
, newChars
));
1373 } else if (!mCharSet
) {
1374 mCharSet
.own(FcCharSetCopy(supportedChars
));
1379 mFonts
.AppendElement(font
);
1380 if (mFonts
.Length() >= i
)
1384 if (mFcFontsTrimmed
== mFcFontSet
->nfont
) {
1385 // finished with this font set
1390 return mFonts
[i
].mPattern
;
1394 * gfxPangoFontset: An implementation of a PangoFontset for gfxPangoFontMap
1397 #define GFX_TYPE_PANGO_FONTSET (gfx_pango_fontset_get_type())
1398 #define GFX_PANGO_FONTSET(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FONTSET, gfxPangoFontset))
1399 #define GFX_IS_PANGO_FONTSET(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FONTSET))
1402 GType
gfx_pango_fontset_get_type (void);
1404 #define GFX_PANGO_FONTSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FONTSET, gfxPangoFontsetClass))
1405 #define GFX_IS_PANGO_FONTSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FONTSET))
1406 #define GFX_PANGO_FONTSET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FONTSET, gfxPangoFontsetClass))
1408 // This struct is POD so that it can be used as a GObject.
1409 struct gfxPangoFontset
{
1410 PangoFontset parent_instance
;
1412 PangoLanguage
*mLanguage
;
1413 gfxFcPangoFontSet
*mGfxFontSet
;
1414 PangoFont
*mBaseFont
;
1415 gfxPangoFontGroup
*mFontGroup
;
1417 static PangoFontset
*
1418 NewFontset(gfxPangoFontGroup
*aFontGroup
,
1419 PangoLanguage
*aLanguage
)
1421 gfxPangoFontset
*fontset
= static_cast<gfxPangoFontset
*>
1422 (g_object_new(GFX_TYPE_PANGO_FONTSET
, NULL
));
1424 fontset
->mLanguage
= aLanguage
;
1426 // Use the font group's fontset if the language matches
1427 if (aFontGroup
->GetPangoLanguage() == aLanguage
) {
1428 fontset
->mGfxFontSet
= aFontGroup
->GetFontSet();
1429 NS_IF_ADDREF(fontset
->mGfxFontSet
);
1432 // Otherwise, fallback fonts depend on the language so get
1433 // another font-set for the language if/when the base font is
1434 // not suitable. Save the font group for this.
1435 fontset
->mFontGroup
= aFontGroup
;
1436 NS_ADDREF(fontset
->mFontGroup
);
1438 // Using the same base font irrespective of the language that
1439 // Pango chooses for the script means that PANGO_SCRIPT_COMMON
1440 // characters are consistently rendered with the same font.
1441 // (Bug 339513 and bug 416725).
1443 // However, use the default Pango behavior (selecting generic
1444 // fonts from the script of the characters) in two situations:
1446 // 1. When we don't have a language to make a good choice for
1447 // the primary font.
1449 // 2. For system fonts, use the default Pango behavior to give
1450 // consistency with other apps. (This probably wouldn't be
1451 // necessary but for bug 91190.)
1452 if (aFontGroup
->GetPangoLanguage() &&
1453 !aFontGroup
->GetStyle()->systemFont
) {
1454 fontset
->mBaseFont
= aFontGroup
->GetBasePangoFont();
1455 if (fontset
->mBaseFont
)
1456 g_object_ref(fontset
->mBaseFont
);
1460 return PANGO_FONTSET(fontset
);
1464 struct gfxPangoFontsetClass
{
1465 PangoFontsetClass parent_class
;
1468 G_DEFINE_TYPE (gfxPangoFontset
, gfx_pango_fontset
, PANGO_TYPE_FONTSET
)
1471 gfx_pango_fontset_init(gfxPangoFontset
*fontset
)
1476 gfx_pango_fontset_finalize(GObject
*object
)
1478 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(object
);
1480 if (self
->mBaseFont
)
1481 g_object_unref(self
->mBaseFont
);
1482 NS_IF_RELEASE(self
->mGfxFontSet
);
1483 NS_IF_RELEASE(self
->mFontGroup
);
1485 G_OBJECT_CLASS(gfx_pango_fontset_parent_class
)->finalize(object
);
1488 static PangoLanguage
*
1489 gfx_pango_fontset_get_language(PangoFontset
*fontset
)
1491 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(fontset
);
1492 return self
->mLanguage
;
1495 static gfxFcPangoFontSet
*
1496 GetGfxFontSet(gfxPangoFontset
*self
)
1498 if (!self
->mGfxFontSet
&& self
->mFontGroup
) {
1499 self
->mGfxFontSet
= self
->mFontGroup
->GetFontSet(self
->mLanguage
);
1500 // Finished with the font group
1501 NS_RELEASE(self
->mFontGroup
);
1503 if (!self
->mGfxFontSet
)
1506 NS_ADDREF(self
->mGfxFontSet
);
1508 return self
->mGfxFontSet
;
1512 gfx_pango_fontset_foreach(PangoFontset
*fontset
, PangoFontsetForeachFunc func
,
1515 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(fontset
);
1517 FcPattern
*baseFontPattern
= NULL
;
1518 if (self
->mBaseFont
) {
1519 if ((*func
)(fontset
, self
->mBaseFont
, data
))
1522 baseFontPattern
= PANGO_FC_FONT(self
->mBaseFont
)->font_pattern
;
1525 // Falling back to secondary fonts
1526 gfxFcPangoFontSet
*gfxFontSet
= GetGfxFontSet(self
);
1530 for (PRUint32 i
= 0;
1531 FcPattern
*pattern
= gfxFontSet
->GetFontPatternAt(i
);
1533 // Skip this font if it is the same face as the base font
1534 if (pattern
== baseFontPattern
) {
1537 PangoFont
*font
= gfxFontSet
->GetFontAt(i
);
1539 if ((*func
)(fontset
, font
, data
))
1545 static PRBool
HasChar(FcPattern
*aFont
, FcChar32 wc
)
1547 FcCharSet
*charset
= NULL
;
1548 FcPatternGetCharSet(aFont
, FC_CHARSET
, 0, &charset
);
1550 return charset
&& FcCharSetHasChar(charset
, wc
);
1554 gfx_pango_fontset_get_font(PangoFontset
*fontset
, guint wc
)
1556 gfxPangoFontset
*self
= GFX_PANGO_FONTSET(fontset
);
1558 PangoFont
*result
= NULL
;
1560 FcPattern
*baseFontPattern
= NULL
;
1561 if (self
->mBaseFont
) {
1562 baseFontPattern
= PANGO_FC_FONT(self
->mBaseFont
)->font_pattern
;
1564 if (HasChar(baseFontPattern
, wc
)) {
1565 result
= self
->mBaseFont
;
1570 // Falling back to secondary fonts
1571 gfxFcPangoFontSet
*gfxFontSet
= GetGfxFontSet(self
);
1574 for (PRUint32 i
= 0;
1575 FcPattern
*pattern
= gfxFontSet
->GetFontPatternAt(i
);
1577 // Skip this font if it is the same face as the base font
1578 if (pattern
== baseFontPattern
) {
1582 if (HasChar(pattern
, wc
)) {
1583 result
= gfxFontSet
->GetFontAt(i
);
1590 // Nothing found. Return the first font.
1591 if (self
->mBaseFont
) {
1592 result
= self
->mBaseFont
;
1593 } else if (gfxFontSet
) {
1594 result
= gfxFontSet
->GetFontAt(0);
1602 g_object_ref(result
);
1607 gfx_pango_fontset_class_init (gfxPangoFontsetClass
*klass
)
1609 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1610 PangoFontsetClass
*fontset_class
= PANGO_FONTSET_CLASS (klass
);
1612 object_class
->finalize
= gfx_pango_fontset_finalize
;
1613 // get_font is not likely to be used but implemented because the class
1614 // makes it available.
1615 fontset_class
->get_font
= gfx_pango_fontset_get_font
;
1616 // inherit fontset_class->get_metrics (which is not likely to be used)
1617 fontset_class
->get_language
= gfx_pango_fontset_get_language
;
1618 fontset_class
->foreach
= gfx_pango_fontset_foreach
;
1622 * gfxPangoFontMap: An implementation of a PangoFontMap.
1624 * This is passed to pango_itemize() through the PangoContext parameter, and
1625 * provides font selection through the gfxPangoFontGroup.
1627 * It is intended that the font group is recorded on the PangoContext with
1628 * SetFontGroup(). The font group is then queried for fonts, with
1629 * gfxFcPangoFontSet doing the font selection.
1632 #define GFX_TYPE_PANGO_FONT_MAP (gfx_pango_font_map_get_type())
1633 #define GFX_PANGO_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMap))
1634 #define GFX_IS_PANGO_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GFX_TYPE_PANGO_FONT_MAP))
1636 GType
gfx_pango_font_map_get_type (void);
1638 #define GFX_PANGO_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
1639 #define GFX_IS_PANGO_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFX_TYPE_PANGO_FONT_MAP))
1640 #define GFX_PANGO_FONT_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFX_TYPE_PANGO_FONT_MAP, gfxPangoFontMapClass))
1642 // Do not instantiate this class directly, but use NewFontMap.
1643 // This struct is POD so that it can be used as a GObject.
1644 struct gfxPangoFontMap
{
1645 PangoFcFontMap parent_instance
;
1647 static PangoFontMap
*
1650 gfxPangoFontMap
*fontmap
= static_cast<gfxPangoFontMap
*>
1651 (g_object_new(GFX_TYPE_PANGO_FONT_MAP
, NULL
));
1653 return PANGO_FONT_MAP(fontmap
);
1657 struct gfxPangoFontMapClass
{
1658 PangoFcFontMapClass parent_class
;
1661 G_DEFINE_TYPE (gfxPangoFontMap
, gfx_pango_font_map
, PANGO_TYPE_FC_FONT_MAP
)
1664 gfx_pango_font_map_init(gfxPangoFontMap
*fontset
)
1669 gfx_pango_font_map_load_font(PangoFontMap
*fontmap
, PangoContext
*context
,
1670 const PangoFontDescription
*description
)
1672 gfxPangoFontGroup
*fontGroup
= GetFontGroup(context
);
1673 if (NS_UNLIKELY(!fontGroup
)) {
1674 return PANGO_FONT_MAP_CLASS(gfx_pango_font_map_parent_class
)->
1675 load_font(fontmap
, context
, description
);
1678 PangoFont
*baseFont
= fontGroup
->GetBasePangoFont();
1679 if (NS_LIKELY(baseFont
)) {
1680 g_object_ref(baseFont
);
1685 static PangoFontset
*
1686 gfx_pango_font_map_load_fontset(PangoFontMap
*fontmap
, PangoContext
*context
,
1687 const PangoFontDescription
*desc
,
1688 PangoLanguage
*language
)
1690 gfxPangoFontGroup
*fontGroup
= GetFontGroup(context
);
1691 if (NS_UNLIKELY(!fontGroup
)) {
1692 return PANGO_FONT_MAP_CLASS(gfx_pango_font_map_parent_class
)->
1693 load_fontset(fontmap
, context
, desc
, language
);
1696 return gfxPangoFontset::NewFontset(fontGroup
, language
);
1700 gfx_pango_font_map_get_resolution(PangoFcFontMap
*fcfontmap
,
1701 PangoContext
*context
)
1703 // This merely enables the FC_SIZE field of the pattern to be accurate.
1704 // We use gfxPlatformGtk::DPI() much of the time...
1705 return gfxPlatformGtk::DPI();
1708 #ifdef MOZ_WIDGET_GTK2
1709 static void ApplyGdkScreenFontOptions(FcPattern
*aPattern
);
1712 // Apply user settings and defaults to pattern in preparation for matching.
1714 PrepareSortPattern(FcPattern
*aPattern
, double aFallbackSize
,
1715 double aSizeAdjustFactor
, PRBool aIsPrinterFont
)
1717 FcConfigSubstitute(NULL
, aPattern
, FcMatchPattern
);
1719 // This gets cairo_font_options_t for the Screen. We should have
1720 // different font options for printing (no hinting) but we are not told
1721 // what we are measuring for.
1723 // If cairo adds support for lcd_filter, gdk will not provide the default
1724 // setting for that option. We could get the default setting by creating
1725 // an xlib surface once, recording its font_options, and then merging the
1728 // Using an xlib surface would also be an option to get Screen font
1729 // options for non-GTK X11 toolkits, but less efficient than using GDK to
1730 // pick up dynamic changes.
1731 if(aIsPrinterFont
) {
1732 cairo_font_options_t
*options
= cairo_font_options_create();
1733 cairo_font_options_set_hint_style (options
, CAIRO_HINT_STYLE_NONE
);
1734 cairo_font_options_set_antialias (options
, CAIRO_ANTIALIAS_GRAY
);
1735 cairo_ft_font_options_substitute(options
, aPattern
);
1736 cairo_font_options_destroy(options
);
1738 #ifdef MOZ_WIDGET_GTK2
1740 ApplyGdkScreenFontOptions(aPattern
);
1744 // Protect against any fontconfig settings that may have incorrectly
1745 // modified the pixelsize, and consider aSizeAdjustFactor.
1746 double size
= aFallbackSize
;
1747 if (FcPatternGetDouble(aPattern
, FC_PIXEL_SIZE
, 0, &size
) != FcResultMatch
1748 || aSizeAdjustFactor
!= 1.0) {
1749 FcPatternDel(aPattern
, FC_PIXEL_SIZE
);
1750 FcPatternAddDouble(aPattern
, FC_PIXEL_SIZE
, size
* aSizeAdjustFactor
);
1753 FcDefaultSubstitute(aPattern
);
1757 gfx_pango_font_map_context_substitute(PangoFcFontMap
*fontmap
,
1758 PangoContext
*context
,
1761 // owned by the context
1762 PangoFontDescription
*desc
= pango_context_get_font_description(context
);
1763 double size
= pango_font_description_get_size(desc
) / FLOAT_PANGO_SCALE
;
1764 gfxPangoFontGroup
*fontGroup
= GetFontGroup(context
);
1765 PRBool usePrinterFont
= fontGroup
&& fontGroup
->GetStyle()->printerFont
;
1766 PrepareSortPattern(pattern
, size
, 1.0, usePrinterFont
);
1769 static PangoFcFont
*
1770 gfx_pango_font_map_create_font(PangoFcFontMap
*fontmap
,
1771 PangoContext
*context
,
1772 const PangoFontDescription
*desc
,
1775 return PANGO_FC_FONT(g_object_new(GFX_TYPE_PANGO_FC_FONT
,
1776 "pattern", pattern
, NULL
));
1780 gfx_pango_font_map_class_init(gfxPangoFontMapClass
*klass
)
1782 // inherit GObjectClass::finalize from parent as this class adds no data.
1784 PangoFontMapClass
*fontmap_class
= PANGO_FONT_MAP_CLASS (klass
);
1785 fontmap_class
->load_font
= gfx_pango_font_map_load_font
;
1786 // inherit fontmap_class->list_families (which is not likely to be used)
1787 // from PangoFcFontMap
1788 fontmap_class
->load_fontset
= gfx_pango_font_map_load_fontset
;
1789 // inherit fontmap_class->shape_engine_type from PangoFcFontMap
1791 PangoFcFontMapClass
*fcfontmap_class
= PANGO_FC_FONT_MAP_CLASS (klass
);
1792 fcfontmap_class
->get_resolution
= gfx_pango_font_map_get_resolution
;
1793 // context_key_* virtual functions are only necessary if we want to
1794 // dynamically respond to changes in the screen cairo_font_options_t.
1796 // context_substitute and get_font are not likely to be used but
1797 // implemented because the class makes them available.
1798 fcfontmap_class
->context_substitute
= gfx_pango_font_map_context_substitute
;
1799 fcfontmap_class
->create_font
= gfx_pango_font_map_create_font
;
1803 ** gfxPangoFontGroup
1806 struct FamilyCallbackData
{
1807 FamilyCallbackData(nsTArray
<nsString
> *aFcFamilyList
,
1808 gfxUserFontSet
*aUserFontSet
)
1809 : mFcFamilyList(aFcFamilyList
), mUserFontSet(aUserFontSet
)
1812 nsTArray
<nsString
> *mFcFamilyList
;
1813 const gfxUserFontSet
*mUserFontSet
;
1817 FFRECountHyphens (const nsAString
&aFFREName
)
1821 while ((hyphen
= aFFREName
.FindChar('-', hyphen
)) >= 0) {
1829 FamilyCallback (const nsAString
& fontName
, const nsACString
& genericName
,
1832 FamilyCallbackData
*data
= static_cast<FamilyCallbackData
*>(closure
);
1833 nsTArray
<nsString
> *list
= data
->mFcFamilyList
;
1835 // We ignore prefs that have three hypens since they are X style prefs.
1836 if (genericName
.Length() && FFRECountHyphens(fontName
) >= 3)
1839 if (!list
->Contains(fontName
)) {
1840 // The family properties of FcPatterns for @font-face fonts have a
1841 // namespace to identify them among system fonts. (see
1842 // FONT_FACE_FAMILY_PREFIX.) The CSS family name can match either the
1843 // @font-face family or the system font family so both names are added
1846 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802 required
1847 // looking for locally-installed fonts matching requested properties
1848 // before checking the src descriptor in @font-face rules.
1849 // http://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#algorithm
1850 // also only checks src descriptors if there is no local font matching
1851 // the requested properties.
1853 // Similarly "Editor's Draft 27 June 2008"
1854 // http://dev.w3.org/csswg/css3-fonts/#font-matching says "The user
1855 // agent attempts to find the family name among fonts available on the
1856 // system and then among fonts defined via @font-face rules."
1857 // However, this is contradicted by "if [the name from the font-family
1858 // descriptor] is the same as a font family available in a given
1859 // user's environment, it effectively hides the underlying font for
1860 // documents that use the stylesheet."
1862 // Windows and Mac code currently prioritizes fonts from @font-face
1863 // rules. The order of families here reflects the priorities on those
1865 const gfxUserFontSet
*userFontSet
= data
->mUserFontSet
;
1866 if (genericName
.Length() == 0 &&
1867 userFontSet
&& userFontSet
->HasFamily(fontName
)) {
1868 nsAutoString userFontName
=
1869 NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX
) + fontName
;
1870 list
->AppendElement(userFontName
);
1873 list
->AppendElement(fontName
);
1879 gfxPangoFontGroup::gfxPangoFontGroup (const nsAString
& families
,
1880 const gfxFontStyle
*aStyle
,
1881 gfxUserFontSet
*aUserFontSet
)
1882 : gfxFontGroup(families
, aStyle
, aUserFontSet
),
1883 mPangoLanguage(GuessPangoLanguage(aStyle
->langGroup
))
1885 mFonts
.AppendElements(1);
1888 gfxPangoFontGroup::~gfxPangoFontGroup()
1893 gfxPangoFontGroup::Copy(const gfxFontStyle
*aStyle
)
1895 return new gfxPangoFontGroup(mFamilies
, aStyle
, mUserFontSet
);
1898 // An array of family names suitable for fontconfig
1900 gfxPangoFontGroup::GetFcFamilies(nsTArray
<nsString
> *aFcFamilyList
,
1901 const nsACString
& aLangGroup
)
1903 FamilyCallbackData
data(aFcFamilyList
, mUserFontSet
);
1904 // Leave non-existing fonts in the list so that fontconfig can get the
1906 ForEachFontInternal(mFamilies
, aLangGroup
, PR_TRUE
, PR_FALSE
,
1907 FamilyCallback
, &data
);
1911 gfxPangoFontGroup::GetBasePangoFont()
1913 return GetBaseFontSet()->GetFontAt(0);
1917 gfxPangoFontGroup::GetFontAt(PRInt32 i
) {
1918 // If it turns out to be hard for all clients that cache font
1919 // groups to call UpdateFontList at appropriate times, we could
1920 // instead consider just calling UpdateFontList from someplace
1921 // more central (such as here).
1922 NS_ASSERTION(!mUserFontSet
|| mCurrGeneration
== GetGeneration(),
1923 "Whoever was caching this font group should have "
1924 "called UpdateFontList on it");
1926 NS_PRECONDITION(i
== 0, "Only have one font");
1929 PangoFont
*pangoFont
= GetBasePangoFont();
1930 mFonts
[0] = gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(pangoFont
));
1937 gfxPangoFontGroup::UpdateFontList()
1942 PRUint64 newGeneration
= mUserFontSet
->GetGeneration();
1943 if (newGeneration
== mCurrGeneration
)
1948 mCurrGeneration
= newGeneration
;
1951 already_AddRefed
<gfxFcPangoFontSet
>
1952 gfxPangoFontGroup::MakeFontSet(PangoLanguage
*aLang
, gfxFloat aSizeAdjustFactor
,
1953 nsAutoRef
<FcPattern
> *aMatchPattern
)
1955 const char *lang
= pango_language_to_string(aLang
);
1957 const char *langGroup
= nsnull
;
1958 if (aLang
!= mPangoLanguage
) {
1959 // Set up langGroup for Mozilla's font prefs.
1960 if (!gLangService
) {
1961 CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID
, &gLangService
);
1965 gLangService
->LookupLanguage(NS_ConvertUTF8toUTF16(lang
));
1967 atom
->GetUTF8String(&langGroup
);
1972 nsAutoTArray
<nsString
, 20> fcFamilyList
;
1973 GetFcFamilies(&fcFamilyList
,
1974 langGroup
? nsDependentCString(langGroup
) : mStyle
.langGroup
);
1976 // To consider: A fontset cache here could be helpful.
1978 // Get a pattern suitable for matching.
1979 nsAutoRef
<FcPattern
> pattern
1980 (gfxFontconfigUtils::NewPattern(fcFamilyList
, mStyle
, lang
));
1982 PrepareSortPattern(pattern
, mStyle
.size
, aSizeAdjustFactor
, mStyle
.printerFont
);
1984 nsRefPtr
<gfxFcPangoFontSet
> fontset
=
1985 new gfxFcPangoFontSet(pattern
, mUserFontSet
);
1988 aMatchPattern
->steal(pattern
);
1990 return fontset
.forget();
1994 FontSetByLangEntry::FontSetByLangEntry(PangoLanguage
*aLang
,
1995 gfxFcPangoFontSet
*aFontSet
)
1996 : mLang(aLang
), mFontSet(aFontSet
)
2001 gfxPangoFontGroup::GetFontSet(PangoLanguage
*aLang
)
2003 GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0]
2006 return mFontSets
[0].mFontSet
;
2008 for (PRUint32 i
= 0; i
< mFontSets
.Length(); ++i
) {
2009 if (mFontSets
[i
].mLang
== aLang
)
2010 return mFontSets
[i
].mFontSet
;
2013 nsRefPtr
<gfxFcPangoFontSet
> fontSet
=
2014 MakeFontSet(aLang
, mSizeAdjustFactor
);
2015 mFontSets
.AppendElement(FontSetByLangEntry(aLang
, fontSet
));
2024 cairo_user_data_key_t
gfxFcFont::sGfxFontKey
;
2026 gfxFcFont::gfxFcFont(cairo_scaled_font_t
*aCairoFont
,
2027 gfxFontEntry
*aFontEntry
,
2028 const gfxFontStyle
*aFontStyle
)
2029 : gfxFont(aFontEntry
, aFontStyle
),
2030 mCairoFont(aCairoFont
),
2031 mHasMetrics(PR_FALSE
)
2033 cairo_scaled_font_reference(mCairoFont
);
2034 cairo_scaled_font_set_user_data(mCairoFont
, &sGfxFontKey
, this, NULL
);
2037 gfxFcFont::~gfxFcFont()
2039 cairo_scaled_font_set_user_data(mCairoFont
, &sGfxFontKey
, NULL
, NULL
);
2040 cairo_scaled_font_destroy(mCairoFont
);
2044 gfxPangoFontGroup::Shutdown()
2046 if (gPangoFontMap
) {
2047 if (PANGO_IS_FC_FONT_MAP (gPangoFontMap
)) {
2048 // This clears circular references from the fontmap to itself
2049 // through its fonts.
2050 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(gPangoFontMap
));
2052 g_object_unref(gPangoFontMap
);
2053 gPangoFontMap
= NULL
;
2056 // Resetting gFTLibrary in case this is wanted again after a
2057 // cairo_debug_reset_static_data.
2060 NS_IF_RELEASE(gLangService
);
2067 // Use cairo's FT_Library so that cairo takes care of shutdown of the
2068 // FT_Library after it has destroyed its font_faces, and FT_Done_Face
2069 // has been called on each FT_Face, at least until this bug is fixed:
2070 // https://bugs.freedesktop.org/show_bug.cgi?id=18857
2072 // Cairo's FT_Library can be obtained from any cairo_scaled_font. The
2073 // font properties requested here are chosen to get an FT_Face that is
2074 // likely to be also used elsewhere.
2076 nsRefPtr
<gfxPangoFontGroup
> fontGroup
=
2077 new gfxPangoFontGroup(NS_LITERAL_STRING("sans-serif"),
2080 gfxFcFont
*font
= static_cast<gfxFcFont
*>(fontGroup
->GetFontAt(0));
2084 LockedFTFace
face(font
);
2088 gFTLibrary
= face
.get()->glyph
->library
;
2094 /* static */ gfxFontEntry
*
2095 gfxPangoFontGroup::NewFontEntry(const gfxProxyFontEntry
&aProxyEntry
,
2096 nsISupports
*aLoader
,
2097 const PRUint8
*aFontData
, PRUint32 aLength
)
2099 // Using face_index = 0 for the first face in the font, as we have no
2100 // other information. FT_New_Memory_Face checks for a NULL FT_Library.
2103 FT_New_Memory_Face(GetFTLibrary(), aFontData
, aLength
, 0, &face
);
2107 return new gfxDownloadedFcFontEntry(aProxyEntry
, aLoader
, face
);
2112 GetPixelSize(FcPattern
*aPattern
)
2115 if (FcPatternGetDouble(aPattern
,
2116 FC_PIXEL_SIZE
, 0, &size
) == FcResultMatch
)
2119 NS_NOTREACHED("No size on pattern");
2124 * The following gfxPangoFonts are accessed from the PangoFont, not from the
2125 * gfxFontCache hash table. The gfxFontCache hash table is keyed by desired
2126 * family and style, whereas here we only know actual family and style. There
2127 * may be more than one of these fonts with the same family and style, but
2128 * different PangoFont and actual font face.
2130 * The point of this is to record the exact font face for gfxTextRun glyph
2131 * indices. The style of this font does not necessarily represent the exact
2132 * gfxFontStyle used to build the text run. Notably, the language is not
2137 already_AddRefed
<gfxFcFont
>
2138 gfxFcFont::GetOrMakeFont(FcPattern
*aPattern
)
2140 cairo_scaled_font_t
*cairoFont
= CreateScaledFont(aPattern
);
2142 nsRefPtr
<gfxFcFont
> font
= static_cast<gfxFcFont
*>
2143 (cairo_scaled_font_get_user_data(cairoFont
, &sGfxFontKey
));
2146 gfxFloat size
= GetPixelSize(aPattern
);
2148 // Shouldn't actually need to take too much care about the correct
2149 // name or style, as size is the only thing expected to be important.
2150 PRUint8 style
= gfxFontconfigUtils::GetThebesStyle(aPattern
);
2151 PRUint16 weight
= gfxFontconfigUtils::GetThebesWeight(aPattern
);
2153 // The LangSet in the FcPattern does not have an order so there is no
2154 // one particular language to choose and converting the set to a
2155 // string through FcNameUnparse() is more trouble than it's worth.
2156 NS_NAMED_LITERAL_CSTRING(langGroup
, "x-unicode");
2157 gfxFontStyle
fontStyle(style
, weight
, size
, langGroup
, 0.0,
2158 PR_TRUE
, PR_FALSE
, PR_FALSE
);
2160 nsRefPtr
<gfxFontEntry
> fe
;
2162 if (FcPatternGetString(aPattern
,
2163 FC_FILE
, 0, &fc_file
) == FcResultMatch
) {
2165 if (FcPatternGetInteger(aPattern
,
2166 FC_INDEX
, 0, &index
) != FcResultMatch
) {
2167 // cairo won't know what to do with this pattern.
2168 NS_NOTREACHED("No index in pattern for font face from file");
2172 // Get a unique name for the font face data from the file and id.
2174 AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file
), name
);
2176 name
.AppendLiteral("/");
2177 name
.AppendInt(index
);
2180 fe
= new gfxFontEntry(name
);
2182 fe
= GetDownloadedFontEntry(aPattern
);
2184 // cairo won't know which font to open without a file.
2185 // (We don't create fonts from an FT_Face.)
2186 NS_NOTREACHED("Fonts without a file is not a web font!?");
2187 fe
= new gfxFontEntry(nsString());
2191 // Note that a file/index pair (or FT_Face) and the gfxFontStyle are
2192 // not necessarily enough to provide a key that will describe a unique
2193 // font. cairoFont contains information from aPattern, which is a
2194 // fully resolved pattern from FcFontRenderPrepare.
2195 // FcFontRenderPrepare takes the requested pattern and the face
2196 // pattern as input and can modify elements of the resulting pattern
2197 // that affect rendering but are not included in the gfxFontStyle.
2198 font
= new gfxFcFont(cairoFont
, fe
, &fontStyle
);
2201 cairo_scaled_font_destroy(cairoFont
);
2202 return font
.forget();
2205 static PangoFontMap
*
2208 if (!gPangoFontMap
) {
2209 gPangoFontMap
= gfxPangoFontMap::NewFontMap();
2211 return gPangoFontMap
;
2214 static PangoContext
*
2217 PangoContext
*context
= pango_context_new();
2218 pango_context_set_font_map(context
, GetPangoFontMap());
2223 gfxPangoFontGroup::GetBaseFontSet()
2225 if (mFontSets
.Length() > 0)
2226 return mFontSets
[0].mFontSet
;
2228 mSizeAdjustFactor
= 1.0; // will be adjusted below if necessary
2229 nsAutoRef
<FcPattern
> pattern
;
2230 nsRefPtr
<gfxFcPangoFontSet
> fontSet
=
2231 MakeFontSet(mPangoLanguage
, mSizeAdjustFactor
, &pattern
);
2233 double size
= GetPixelSize(pattern
);
2234 if (size
!= 0.0 && mStyle
.sizeAdjust
!= 0.0) {
2236 gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(fontSet
->GetFontAt(0)));
2238 const gfxFont::Metrics
& metrics
= font
->GetMetrics();
2240 // The factor of 0.1 ensures that xHeight is sane so fonts don't
2241 // become huge. Strictly ">" ensures that xHeight and emHeight are
2243 if (metrics
.xHeight
> 0.1 * metrics
.emHeight
) {
2245 mStyle
.sizeAdjust
* metrics
.emHeight
/ metrics
.xHeight
;
2247 size
*= mSizeAdjustFactor
;
2248 FcPatternDel(pattern
, FC_PIXEL_SIZE
);
2249 FcPatternAddDouble(pattern
, FC_PIXEL_SIZE
, size
);
2251 fontSet
= new gfxFcPangoFontSet(pattern
, mUserFontSet
);
2256 PangoLanguage
*pangoLang
= mPangoLanguage
;
2259 FcPatternGetString(pattern
, FC_LANG
, 0, &fcLang
) == FcResultMatch
) {
2261 pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang
));
2264 mFontSets
.AppendElement(FontSetByLangEntry(pangoLang
, fontSet
));
2270 gfxFcFont::GetGlyphExtents(PRUint32 aGlyph
, cairo_text_extents_t
* aExtents
)
2272 NS_PRECONDITION(aExtents
!= NULL
, "aExtents must not be NULL");
2274 cairo_glyph_t glyphs
[1];
2275 glyphs
[0].index
= aGlyph
;
2278 // cairo does some caching for us here but perhaps a small gain could be
2279 // made by caching more. It is usually only the advance that is needed,
2280 // so caching only the advance could allow many requests to be cached with
2281 // little memory use. Ideally this cache would be merged with
2283 cairo_scaled_font_glyph_extents(CairoScaledFont(), glyphs
, 1, aExtents
);
2287 LockedFTFace::GetCharExtents(char aChar
,
2288 cairo_text_extents_t
* aExtents
)
2290 NS_PRECONDITION(aExtents
!= NULL
, "aExtents must not be NULL");
2295 // pango_fc_font_real_get_glyph uses FcFreeTypeCharIndex which may change
2296 // the charmap currently selected on the FT_Face, so, while
2297 // pango_fc_font_real_get_glyph might be used, we should use the same
2298 // function so as to search the charmaps.
2300 // Unfortunately this considers the mac/roman cmap even when there is a
2301 // unicode cmap, which will be bad for symbol fonts, so we should do this
2302 // ourselves, perhaps with a lightweight cache like
2303 // pango_fc_font_real_get_glyph uses.
2304 FT_UInt gid
= FcFreeTypeCharIndex(mFace
, aChar
); // glyph id
2306 mGfxFont
->GetGlyphExtents(gid
, aExtents
);
2312 // Snap a line to pixels while keeping the center and size of the line as
2313 // close to the original position as possible.
2315 // Pango does similar snapping for underline and strikethrough when fonts are
2316 // hinted, but nsCSSRendering::GetTextDecorationRectInternal always snaps the
2317 // top and size of lines. Optimizing the distance between the line and
2318 // baseline is probably good for the gap between text and underline, but
2319 // optimizing the center of the line is better for positioning strikethough.
2321 SnapLineToPixels(gfxFloat
& aOffset
, gfxFloat
& aSize
)
2323 gfxFloat snappedSize
= PR_MAX(NS_floor(aSize
+ 0.5), 1.0);
2324 // Correct offset for change in size
2325 gfxFloat offset
= aOffset
- 0.5 * (aSize
- snappedSize
);
2327 aOffset
= NS_floor(offset
+ 0.5);
2328 aSize
= snappedSize
;
2332 LockedFTFace::GetMetrics(gfxFont::Metrics
* aMetrics
, PRUint32
* aSpaceGlyph
)
2334 NS_PRECONDITION(aMetrics
!= NULL
, "aMetrics must not be NULL");
2335 NS_PRECONDITION(aSpaceGlyph
!= NULL
, "aSpaceGlyph must not be NULL");
2337 if (NS_UNLIKELY(!mFace
)) {
2338 // No face. This unfortunate situation might happen if the font
2339 // file is (re)moved at the wrong time.
2340 aMetrics
->emHeight
= mGfxFont
->GetStyle()->size
;
2341 aMetrics
->emAscent
= 0.8 * aMetrics
->emHeight
;
2342 aMetrics
->emDescent
= 0.2 * aMetrics
->emHeight
;
2343 aMetrics
->maxAscent
= aMetrics
->emAscent
;
2344 aMetrics
->maxDescent
= aMetrics
->maxDescent
;
2345 aMetrics
->maxHeight
= aMetrics
->emHeight
;
2346 aMetrics
->internalLeading
= 0.0;
2347 aMetrics
->externalLeading
= 0.2 * aMetrics
->emHeight
;
2349 aMetrics
->spaceWidth
= 0.5 * aMetrics
->emHeight
;
2350 aMetrics
->maxAdvance
= aMetrics
->spaceWidth
;
2351 aMetrics
->aveCharWidth
= aMetrics
->spaceWidth
;
2352 aMetrics
->zeroOrAveCharWidth
= aMetrics
->spaceWidth
;
2353 aMetrics
->xHeight
= 0.5 * aMetrics
->emHeight
;
2354 aMetrics
->underlineSize
= aMetrics
->emHeight
/ 14.0;
2355 aMetrics
->underlineOffset
= -aMetrics
->underlineSize
;
2356 aMetrics
->strikeoutOffset
= 0.25 * aMetrics
->emHeight
;
2357 aMetrics
->strikeoutSize
= aMetrics
->underlineSize
;
2358 aMetrics
->superscriptOffset
= aMetrics
->xHeight
;
2359 aMetrics
->subscriptOffset
= aMetrics
->xHeight
;
2364 const FT_Size_Metrics
& ftMetrics
= mFace
->size
->metrics
;
2367 // Scale for vertical design metric conversion: pixels per design unit.
2369 if (FT_IS_SCALABLE(mFace
)) {
2370 // Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not
2371 // have subpixel accuracy.
2373 // FT_Size_Metrics::y_scale is in 16.16 fixed point format. Its
2374 // (fractional) value is a factor that converts vertical metrics from
2375 // design units to units of 1/64 pixels, so that the result may be
2376 // interpreted as pixels in 26.6 fixed point format.
2377 yScale
= FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics
.y_scale
));
2378 emHeight
= mFace
->units_per_EM
* yScale
;
2379 } else { // Not scalable.
2380 // FT_Size_Metrics doc says x_scale is "only relevant for scalable
2382 gfxFloat emUnit
= mFace
->units_per_EM
;
2383 emHeight
= ftMetrics
.y_ppem
;
2384 yScale
= emHeight
/ emUnit
;
2388 static_cast<TT_OS2
*>(FT_Get_Sfnt_Table(mFace
, ft_sfnt_os2
));
2390 aMetrics
->maxAscent
= FLOAT_FROM_26_6(ftMetrics
.ascender
);
2391 aMetrics
->maxDescent
= -FLOAT_FROM_26_6(ftMetrics
.descender
);
2392 aMetrics
->maxAdvance
= FLOAT_FROM_26_6(ftMetrics
.max_advance
);
2394 gfxFloat lineHeight
;
2395 if (os2
&& os2
->sTypoAscender
) {
2396 aMetrics
->emAscent
= os2
->sTypoAscender
* yScale
;
2397 aMetrics
->emDescent
= -os2
->sTypoDescender
* yScale
;
2398 FT_Short typoHeight
=
2399 os2
->sTypoAscender
- os2
->sTypoDescender
+ os2
->sTypoLineGap
;
2400 lineHeight
= typoHeight
* yScale
;
2402 // maxAscent/maxDescent get used for frame heights, and some fonts
2403 // don't have the HHEA table ascent/descent set (bug 279032).
2404 if (aMetrics
->emAscent
> aMetrics
->maxAscent
)
2405 aMetrics
->maxAscent
= aMetrics
->emAscent
;
2406 if (aMetrics
->emDescent
> aMetrics
->maxDescent
)
2407 aMetrics
->maxDescent
= aMetrics
->emDescent
;
2409 aMetrics
->emAscent
= aMetrics
->maxAscent
;
2410 aMetrics
->emDescent
= aMetrics
->maxDescent
;
2411 lineHeight
= FLOAT_FROM_26_6(ftMetrics
.height
);
2414 cairo_text_extents_t extents
;
2415 *aSpaceGlyph
= GetCharExtents(' ', &extents
);
2417 aMetrics
->spaceWidth
= extents
.x_advance
;
2419 aMetrics
->spaceWidth
= aMetrics
->maxAdvance
; // guess
2422 aMetrics
->zeroOrAveCharWidth
= 0.0;
2423 if (GetCharExtents('0', &extents
)) {
2424 aMetrics
->zeroOrAveCharWidth
= extents
.x_advance
;
2427 // Prefering a measured x over sxHeight because sxHeight doesn't consider
2428 // hinting, but maybe the x extents are not quite right in some fancy
2429 // script fonts. CSS 2.1 suggests possibly using the height of an "o",
2430 // which would have a more consistent glyph across fonts.
2431 if (GetCharExtents('x', &extents
) && extents
.y_bearing
< 0.0) {
2432 aMetrics
->xHeight
= -extents
.y_bearing
;
2433 aMetrics
->aveCharWidth
= extents
.x_advance
;
2435 if (os2
&& os2
->sxHeight
) {
2436 aMetrics
->xHeight
= os2
->sxHeight
* yScale
;
2438 // CSS 2.1, section 4.3.2 Lengths: "In the cases where it is
2439 // impossible or impractical to determine the x-height, a value of
2440 // 0.5em should be used."
2441 aMetrics
->xHeight
= 0.5 * emHeight
;
2443 aMetrics
->aveCharWidth
= 0.0; // updated below
2445 // aveCharWidth is used for the width of text input elements so be
2446 // liberal rather than conservative in the estimate.
2447 if (os2
&& os2
->xAvgCharWidth
) {
2448 // Round to pixels as this is compared with maxAdvance to guess
2449 // whether this is a fixed width font.
2450 gfxFloat avgCharWidth
=
2451 ScaleRoundDesignUnits(os2
->xAvgCharWidth
, ftMetrics
.x_scale
);
2452 aMetrics
->aveCharWidth
=
2453 PR_MAX(aMetrics
->aveCharWidth
, avgCharWidth
);
2455 aMetrics
->aveCharWidth
=
2456 PR_MAX(aMetrics
->aveCharWidth
, aMetrics
->zeroOrAveCharWidth
);
2457 if (aMetrics
->aveCharWidth
== 0.0) {
2458 aMetrics
->aveCharWidth
= aMetrics
->spaceWidth
;
2460 if (aMetrics
->zeroOrAveCharWidth
== 0.0) {
2461 aMetrics
->zeroOrAveCharWidth
= aMetrics
->aveCharWidth
;
2463 // Apparently hinting can mean that max_advance is not always accurate.
2464 aMetrics
->maxAdvance
=
2465 PR_MAX(aMetrics
->maxAdvance
, aMetrics
->aveCharWidth
);
2467 // gfxFont::Metrics::underlineOffset is the position of the top of the
2470 // FT_FaceRec documentation describes underline_position as "the
2471 // center of the underlining stem". This was the original definition
2472 // of the PostScript metric, but in the PostScript table of OpenType
2473 // fonts the metric is "the top of the underline"
2474 // (http://www.microsoft.com/typography/otspec/post.htm), and FreeType
2475 // (up to version 2.3.7) doesn't make any adjustment.
2477 // Therefore get the underline position directly from the table
2478 // ourselves when this table exists. Use FreeType's metrics for
2479 // other (including older PostScript) fonts.
2480 if (mFace
->underline_position
&& mFace
->underline_thickness
) {
2481 aMetrics
->underlineSize
= mFace
->underline_thickness
* yScale
;
2482 TT_Postscript
*post
= static_cast<TT_Postscript
*>
2483 (FT_Get_Sfnt_Table(mFace
, ft_sfnt_post
));
2484 if (post
&& post
->underlinePosition
) {
2485 aMetrics
->underlineOffset
= post
->underlinePosition
* yScale
;
2487 aMetrics
->underlineOffset
= mFace
->underline_position
* yScale
2488 + 0.5 * aMetrics
->underlineSize
;
2490 } else { // No underline info.
2492 aMetrics
->underlineSize
= emHeight
/ 14.0;
2493 aMetrics
->underlineOffset
= -aMetrics
->underlineSize
;
2496 if (os2
&& os2
->yStrikeoutSize
&& os2
->yStrikeoutPosition
) {
2497 aMetrics
->strikeoutSize
= os2
->yStrikeoutSize
* yScale
;
2498 aMetrics
->strikeoutOffset
= os2
->yStrikeoutPosition
* yScale
;
2499 } else { // No strikeout info.
2500 aMetrics
->strikeoutSize
= aMetrics
->underlineSize
;
2501 // Use OpenType spec's suggested position for Roman font.
2502 aMetrics
->strikeoutOffset
= emHeight
* 409.0 / 2048.0
2503 + 0.5 * aMetrics
->strikeoutSize
;
2505 SnapLineToPixels(aMetrics
->strikeoutOffset
, aMetrics
->strikeoutSize
);
2507 if (os2
&& os2
->ySuperscriptYOffset
) {
2508 gfxFloat val
= ScaleRoundDesignUnits(os2
->ySuperscriptYOffset
,
2510 aMetrics
->superscriptOffset
= PR_MAX(1.0, val
);
2512 aMetrics
->superscriptOffset
= aMetrics
->xHeight
;
2515 if (os2
&& os2
->ySubscriptYOffset
) {
2516 gfxFloat val
= ScaleRoundDesignUnits(os2
->ySubscriptYOffset
,
2518 // some fonts have the incorrect sign.
2520 aMetrics
->subscriptOffset
= PR_MAX(1.0, val
);
2522 aMetrics
->subscriptOffset
= aMetrics
->xHeight
;
2525 aMetrics
->maxHeight
= aMetrics
->maxAscent
+ aMetrics
->maxDescent
;
2527 // Make the line height an integer number of pixels so that lines will be
2528 // equally spaced (rather than just being snapped to pixels, some up and
2529 // some down). Layout calculates line height from the emHeight +
2530 // internalLeading + externalLeading, but first each of these is rounded
2531 // to layout units. To ensure that the result is an integer number of
2532 // pixels, round each of the components to pixels.
2533 aMetrics
->emHeight
= NS_floor(emHeight
+ 0.5);
2535 // maxHeight will normally be an integer, but round anyway in case
2536 // FreeType is configured differently.
2537 aMetrics
->internalLeading
=
2538 NS_floor(aMetrics
->maxHeight
- aMetrics
->emHeight
+ 0.5);
2540 // Text input boxes currently don't work well with lineHeight
2541 // significantly less than maxHeight (with Verdana, for example).
2542 lineHeight
= NS_floor(PR_MAX(lineHeight
, aMetrics
->maxHeight
) + 0.5);
2543 aMetrics
->externalLeading
=
2544 lineHeight
- aMetrics
->internalLeading
- aMetrics
->emHeight
;
2546 // Ensure emAscent + emDescent == emHeight
2547 gfxFloat sum
= aMetrics
->emAscent
+ aMetrics
->emDescent
;
2548 aMetrics
->emAscent
= sum
> 0.0 ?
2549 aMetrics
->emAscent
* aMetrics
->emHeight
/ sum
: 0.0;
2550 aMetrics
->emDescent
= aMetrics
->emHeight
- aMetrics
->emAscent
;
2553 const gfxFont::Metrics
&
2554 gfxFcFont::GetMetrics()
2559 if (NS_UNLIKELY(GetStyle()->size
<= 0.0)) {
2560 new(&mMetrics
) gfxFont::Metrics(); // zero initialize
2563 LockedFTFace(this).GetMetrics(&mMetrics
, &mSpaceGlyph
);
2566 SanitizeMetrics(&mMetrics
, PR_FALSE
);
2569 // printf("font name: %s %f\n", NS_ConvertUTF16toUTF8(GetName()).get(), GetStyle()->size);
2570 // printf ("pango font %s\n", pango_font_description_to_string (pango_font_describe (font)));
2572 fprintf (stderr
, "Font: %s\n", NS_ConvertUTF16toUTF8(GetName()).get());
2573 fprintf (stderr
, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics
.emHeight
, mMetrics
.emAscent
, mMetrics
.emDescent
);
2574 fprintf (stderr
, " maxAscent: %f maxDescent: %f\n", mMetrics
.maxAscent
, mMetrics
.maxDescent
);
2575 fprintf (stderr
, " internalLeading: %f externalLeading: %f\n", mMetrics
.externalLeading
, mMetrics
.internalLeading
);
2576 fprintf (stderr
, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics
.spaceWidth
, mMetrics
.aveCharWidth
, mMetrics
.xHeight
);
2577 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
);
2580 mHasMetrics
= PR_TRUE
;
2585 gfxFcFont::GetUniqueName()
2593 * A serious problem:
2595 * -- We draw with a font that's hinted for the CTM, but we measure with a font
2596 * hinted to the identity matrix, so our "bounding metrics" may not be accurate.
2601 * We use this to append an LTR or RTL Override character to the start of the
2602 * string. This forces Pango to honour our direction even if there are neutral characters
2605 static PRInt32
AppendDirectionalIndicatorUTF8(PRBool aIsRTL
, nsACString
& aString
)
2607 static const PRUnichar overrides
[2][2] =
2608 { { 0x202d, 0 }, { 0x202e, 0 }}; // LRO, RLO
2609 AppendUTF16toUTF8(overrides
[aIsRTL
], aString
);
2610 return 3; // both overrides map to 3 bytes in UTF8
2614 gfxPangoFontGroup::MakeTextRun(const PRUint8
*aString
, PRUint32 aLength
,
2615 const Parameters
*aParams
, PRUint32 aFlags
)
2617 NS_ASSERTION(aFlags
& TEXT_IS_8BIT
, "8bit should have been set");
2618 gfxTextRun
*run
= gfxTextRun::Create(aParams
, aString
, aLength
, this, aFlags
);
2622 PRBool isRTL
= run
->IsRightToLeft();
2623 if ((aFlags
& TEXT_IS_ASCII
) && !isRTL
) {
2624 // We don't need to send an override character here, the characters must be all LTR
2625 const gchar
*utf8Chars
= reinterpret_cast<const gchar
*>(aString
);
2626 InitTextRun(run
, utf8Chars
, aLength
, 0, PR_TRUE
);
2628 // this is really gross...
2629 const char *chars
= reinterpret_cast<const char*>(aString
);
2630 NS_ConvertASCIItoUTF16
unicodeString(chars
, aLength
);
2632 PRInt32 headerLen
= AppendDirectionalIndicatorUTF8(isRTL
, utf8
);
2633 AppendUTF16toUTF8(unicodeString
, utf8
);
2634 InitTextRun(run
, utf8
.get(), utf8
.Length(), headerLen
, PR_TRUE
);
2636 run
->FetchGlyphExtents(aParams
->mContext
);
2640 #if defined(ENABLE_FAST_PATH_8BIT)
2642 gfxPangoFontGroup::CanTakeFastPath(PRUint32 aFlags
)
2644 // Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't.
2645 // We need to always use Pango for RTL text, in case glyph mirroring is
2647 PRBool speed
= aFlags
& gfxTextRunFactory::TEXT_OPTIMIZE_SPEED
;
2648 PRBool isRTL
= aFlags
& gfxTextRunFactory::TEXT_IS_RTL
;
2649 return speed
&& !isRTL
&& PANGO_IS_FC_FONT(GetBasePangoFont());
2654 gfxPangoFontGroup::MakeTextRun(const PRUnichar
*aString
, PRUint32 aLength
,
2655 const Parameters
*aParams
, PRUint32 aFlags
)
2657 gfxTextRun
*run
= gfxTextRun::Create(aParams
, aString
, aLength
, this, aFlags
);
2661 run
->RecordSurrogates(aString
);
2664 PRInt32 headerLen
= AppendDirectionalIndicatorUTF8(run
->IsRightToLeft(), utf8
);
2665 AppendUTF16toUTF8(Substring(aString
, aString
+ aLength
), utf8
);
2666 PRBool is8Bit
= PR_FALSE
;
2668 #if defined(ENABLE_FAST_PATH_8BIT)
2669 if (CanTakeFastPath(aFlags
)) {
2670 PRUint32 allBits
= 0;
2672 for (i
= 0; i
< aLength
; ++i
) {
2673 allBits
|= aString
[i
];
2675 is8Bit
= (allBits
& 0xFF00) == 0;
2678 InitTextRun(run
, utf8
.get(), utf8
.Length(), headerLen
, is8Bit
);
2679 run
->FetchGlyphExtents(aParams
->mContext
);
2684 gfxPangoFontGroup::InitTextRun(gfxTextRun
*aTextRun
, const gchar
*aUTF8Text
,
2685 PRUint32 aUTF8Length
, PRUint32 aUTF8HeaderLength
,
2686 PRBool aTake8BitPath
)
2688 #if defined(ENABLE_FAST_PATH_ALWAYS)
2689 CreateGlyphRunsFast(aTextRun
, aUTF8Text
+ aUTF8HeaderLength
, aUTF8Length
- aUTF8HeaderLength
);
2691 #if defined(ENABLE_FAST_PATH_8BIT)
2692 if (aTake8BitPath
&& CanTakeFastPath(aTextRun
->GetFlags())) {
2693 nsresult rv
= CreateGlyphRunsFast(aTextRun
, aUTF8Text
+ aUTF8HeaderLength
, aUTF8Length
- aUTF8HeaderLength
);
2694 if (NS_SUCCEEDED(rv
))
2699 CreateGlyphRunsItemizing(aTextRun
, aUTF8Text
, aUTF8Length
, aUTF8HeaderLength
);
2703 static void ReleaseDownloadedFontEntry(void *data
)
2705 gfxDownloadedFcFontEntry
*downloadedFontEntry
=
2706 static_cast<gfxDownloadedFcFontEntry
*>(data
);
2707 NS_RELEASE(downloadedFontEntry
);
2710 // This will fetch an existing scaled_font if one exists.
2711 static cairo_scaled_font_t
*
2712 CreateScaledFont(FcPattern
*aPattern
)
2714 cairo_font_face_t
*face
= cairo_ft_font_face_create_for_pattern(aPattern
);
2716 // If the face is created from a web font entry, hold a reference to the
2717 // font entry to keep the font face data.
2718 gfxDownloadedFcFontEntry
*downloadedFontEntry
=
2719 GetDownloadedFontEntry(aPattern
);
2720 if (downloadedFontEntry
&&
2721 cairo_font_face_status(face
) == CAIRO_STATUS_SUCCESS
) {
2722 static cairo_user_data_key_t sFontEntryKey
;
2724 // Check whether this is a new cairo face
2725 void *currentEntry
=
2726 cairo_font_face_get_user_data(face
, &sFontEntryKey
);
2727 if (!currentEntry
) {
2728 NS_ADDREF(downloadedFontEntry
);
2729 cairo_font_face_set_user_data(face
, &sFontEntryKey
,
2730 downloadedFontEntry
,
2731 ReleaseDownloadedFontEntry
);
2733 NS_ASSERTION(currentEntry
== downloadedFontEntry
,
2734 "Unexpected cairo font face!");
2738 double size
= GetPixelSize(aPattern
);
2740 cairo_matrix_t fontMatrix
;
2742 if (FcPatternGetMatrix(aPattern
, FC_MATRIX
, 0, &fcMatrix
) == FcResultMatch
)
2743 cairo_matrix_init(&fontMatrix
, fcMatrix
->xx
, -fcMatrix
->yx
, -fcMatrix
->xy
, fcMatrix
->yy
, 0, 0);
2745 cairo_matrix_init_identity(&fontMatrix
);
2746 cairo_matrix_scale(&fontMatrix
, size
, size
);
2748 // The cairo_scaled_font is created with a unit ctm so that metrics and
2749 // positions are in user space, but this means that hinting effects will
2750 // not be estimated accurately for non-unit transformations.
2751 cairo_matrix_t identityMatrix
;
2752 cairo_matrix_init_identity(&identityMatrix
);
2754 // Font options are set explicitly here to improve cairo's caching
2755 // behavior and to record the relevant parts of the pattern for
2756 // SetupCairoFont (so that the pattern can be released).
2758 // Most font_options have already been set as defaults on the FcPattern
2759 // with cairo_ft_font_options_substitute(), then user and system
2760 // fontconfig configurations were applied. The resulting font_options
2761 // have been recorded on the face during
2762 // cairo_ft_font_face_create_for_pattern().
2764 // None of the settings here cause this scaled_font to behave any
2765 // differently from how it would behave if it were created from the same
2766 // face with default font_options.
2768 // We set options explicitly so that the same scaled_font will be found in
2769 // the cairo_scaled_font_map when cairo loads glyphs from a context with
2770 // the same font_face, font_matrix, ctm, and surface font_options.
2772 // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
2773 // font_options on the cairo_ft_font_face, and doesn't consider default
2774 // option values to not match any explicit values.
2776 // Even after cairo_set_scaled_font is used to set font_options for the
2777 // cairo context, when cairo looks for a scaled_font for the context, it
2778 // will look for a font with some option values from the target surface if
2779 // any values are left default on the context font_options. If this
2780 // scaled_font is created with default font_options, cairo will not find
2782 cairo_font_options_t
*fontOptions
= cairo_font_options_create();
2784 // The one option not recorded in the pattern is hint_metrics, which will
2785 // affect glyph metrics. The default behaves as CAIRO_HINT_METRICS_ON.
2786 // We should be considering the font_options of the surface on which this
2787 // font will be used, but currently we don't have different gfxFonts for
2788 // different surface font_options, so we'll create a font suitable for the
2789 // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
2790 cairo_font_options_set_hint_metrics(fontOptions
, CAIRO_HINT_METRICS_ON
);
2792 // The remaining options have been recorded on the pattern and the face.
2793 // _cairo_ft_options_merge has some logic to decide which options from the
2794 // scaled_font or from the cairo_ft_font_face take priority in the way the
2797 // In the majority of cases, _cairo_ft_options_merge uses the options from
2798 // the cairo_ft_font_face, so sometimes it is not so important which
2799 // values are set here so long as they are not defaults, but we'll set
2800 // them to the exact values that we expect from the font, to be consistent
2801 // and to protect against changes in cairo.
2803 // In some cases, _cairo_ft_options_merge uses some options from the
2804 // scaled_font's font_options rather than options on the
2805 // cairo_ft_font_face (from fontconfig).
2806 // https://bugs.freedesktop.org/show_bug.cgi?id=11838
2808 // Surface font options were set on the pattern in
2809 // cairo_ft_font_options_substitute. If fontconfig has changed the
2810 // hint_style then that is what the user (or distribution) wants, so we
2811 // use the setting from the FcPattern.
2813 // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
2815 if (FcPatternGetBool(aPattern
, FC_HINTING
, 0, &hinting
) != FcResultMatch
) {
2818 cairo_hint_style_t hint_style
;
2820 hint_style
= CAIRO_HINT_STYLE_NONE
;
2822 #ifdef FC_HINT_STYLE // FC_HINT_STYLE is available from fontconfig 2.2.91.
2824 if (FcPatternGetInteger(aPattern
, FC_HINT_STYLE
,
2825 0, &fc_hintstyle
) != FcResultMatch
) {
2826 fc_hintstyle
= FC_HINT_FULL
;
2828 switch (fc_hintstyle
) {
2830 hint_style
= CAIRO_HINT_STYLE_NONE
;
2832 case FC_HINT_SLIGHT
:
2833 hint_style
= CAIRO_HINT_STYLE_SLIGHT
;
2835 case FC_HINT_MEDIUM
:
2836 default: // This fallback mirrors _get_pattern_ft_options in cairo.
2837 hint_style
= CAIRO_HINT_STYLE_MEDIUM
;
2840 hint_style
= CAIRO_HINT_STYLE_FULL
;
2843 #else // no FC_HINT_STYLE
2844 hint_style
= CAIRO_HINT_STYLE_FULL
;
2847 cairo_font_options_set_hint_style(fontOptions
, hint_style
);
2850 if (FcPatternGetInteger(aPattern
,
2851 FC_RGBA
, 0, &rgba
) != FcResultMatch
) {
2852 rgba
= FC_RGBA_UNKNOWN
;
2854 cairo_subpixel_order_t subpixel_order
= CAIRO_SUBPIXEL_ORDER_DEFAULT
;
2856 case FC_RGBA_UNKNOWN
:
2859 // There is no CAIRO_SUBPIXEL_ORDER_NONE. Subpixel antialiasing
2860 // is disabled through cairo_antialias_t.
2861 rgba
= FC_RGBA_NONE
;
2862 // subpixel_order won't be used by the font as we won't use
2863 // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
2864 // caching reasons described above. Fall through:
2866 subpixel_order
= CAIRO_SUBPIXEL_ORDER_RGB
;
2869 subpixel_order
= CAIRO_SUBPIXEL_ORDER_BGR
;
2872 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VRGB
;
2875 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VBGR
;
2878 cairo_font_options_set_subpixel_order(fontOptions
, subpixel_order
);
2880 FcBool fc_antialias
;
2881 if (FcPatternGetBool(aPattern
,
2882 FC_ANTIALIAS
, 0, &fc_antialias
) != FcResultMatch
) {
2883 fc_antialias
= FcTrue
;
2885 cairo_antialias_t antialias
;
2886 if (!fc_antialias
) {
2887 antialias
= CAIRO_ANTIALIAS_NONE
;
2888 } else if (rgba
== FC_RGBA_NONE
) {
2889 antialias
= CAIRO_ANTIALIAS_GRAY
;
2891 antialias
= CAIRO_ANTIALIAS_SUBPIXEL
;
2893 cairo_font_options_set_antialias(fontOptions
, antialias
);
2895 cairo_scaled_font_t
*scaledFont
=
2896 cairo_scaled_font_create(face
, &fontMatrix
, &identityMatrix
,
2899 cairo_font_options_destroy(fontOptions
);
2900 cairo_font_face_destroy(face
);
2902 NS_ASSERTION(cairo_scaled_font_status(scaledFont
) == CAIRO_STATUS_SUCCESS
,
2903 "Failed to create scaled font");
2908 gfxFcFont::SetupCairoFont(gfxContext
*aContext
)
2910 cairo_t
*cr
= aContext
->GetCairo();
2912 // The scaled font ctm is not relevant right here because
2913 // cairo_set_scaled_font does not record the scaled font itself, but
2914 // merely the font_face, font_matrix, font_options. The scaled_font used
2915 // for the target can be different from the scaled_font passed to
2916 // cairo_set_scaled_font. (Unfortunately we have measured only for an
2918 cairo_scaled_font_t
*cairoFont
= CairoScaledFont();
2920 if (cairo_scaled_font_status(cairoFont
) != CAIRO_STATUS_SUCCESS
) {
2921 // Don't cairo_set_scaled_font as that would propagate the error to
2922 // the cairo_t, precluding any further drawing.
2925 // Thoughts on which font_options to set on the context:
2927 // cairoFont has been created for screen rendering.
2929 // When the context is being used for screen rendering, we should set
2930 // font_options such that the same scaled_font gets used (when the ctm is
2931 // the same). The use of explicit font_options recorded in
2932 // CreateScaledFont ensures that this will happen.
2934 // XXXkt: For pdf and ps surfaces, I don't know whether it's better to
2935 // remove surface-specific options, or try to draw with the same
2936 // scaled_font that was used to measure. As the same font_face is being
2937 // used, its font_options will often override some values anyway (unless
2938 // perhaps we remove those from the FcPattern at face creation).
2940 // I can't see any significant difference in printing, irrespective of
2941 // what is set here. It's too late to change things here as measuring has
2942 // already taken place. We should really be measuring with a different
2943 // font for pdf and ps surfaces (bug 403513).
2944 cairo_set_scaled_font(cr
, cairoFont
);
2949 SetupClusterBoundaries(gfxTextRun
* aTextRun
, const gchar
*aUTF8
, PRUint32 aUTF8Length
,
2950 PRUint32 aUTF16Offset
, PangoAnalysis
*aAnalysis
)
2952 if (aTextRun
->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT
) {
2953 // 8-bit text doesn't have clusters.
2954 // XXX is this true in all languages???
2955 // behdad: don't think so. Czech for example IIRC has a
2960 // Pango says "the array of PangoLogAttr passed in must have at least N+1
2961 // elements, if there are N characters in the text being broken".
2962 // Could use g_utf8_strlen(aUTF8, aUTF8Length) + 1 but the memory savings
2963 // may not be worth the call.
2964 nsAutoTArray
<PangoLogAttr
,2000> buffer
;
2965 if (!buffer
.AppendElements(aUTF8Length
+ 1))
2968 pango_break(aUTF8
, aUTF8Length
, aAnalysis
,
2969 buffer
.Elements(), buffer
.Length());
2971 const gchar
*p
= aUTF8
;
2972 const gchar
*end
= aUTF8
+ aUTF8Length
;
2973 const PangoLogAttr
*attr
= buffer
.Elements();
2974 gfxTextRun::CompressedGlyph g
;
2976 if (!attr
->is_cursor_position
) {
2977 aTextRun
->SetGlyphs(aUTF16Offset
, g
.SetComplex(PR_FALSE
, PR_TRUE
, 0), nsnull
);
2981 gunichar ch
= g_utf8_get_char(p
);
2982 NS_ASSERTION(ch
!= 0, "Shouldn't have NUL in pango_break");
2983 NS_ASSERTION(!IS_SURROGATE(ch
), "Shouldn't have surrogates in UTF8");
2984 if (ch
>= 0x10000) {
2985 // set glyph info for the UTF-16 low surrogate
2986 aTextRun
->SetGlyphs(aUTF16Offset
, g
.SetComplex(PR_FALSE
, PR_FALSE
, 0), nsnull
);
2989 // We produced this utf8 so we don't need to worry about malformed stuff
2990 p
= g_utf8_next_char(p
);
2996 ConvertPangoToAppUnits(PRInt32 aCoordinate
, PRUint32 aAppUnitsPerDevUnit
)
2998 PRInt64 v
= (PRInt64(aCoordinate
)*aAppUnitsPerDevUnit
+ PANGO_SCALE
/2)/PANGO_SCALE
;
3003 * Given a run of Pango glyphs that should be treated as a single
3004 * cluster/ligature, store them in the textrun at the appropriate character
3005 * and set the other characters involved to be ligature/cluster continuations
3009 SetGlyphsForCharacterGroup(const PangoGlyphInfo
*aGlyphs
, PRUint32 aGlyphCount
,
3010 gfxTextRun
*aTextRun
,
3011 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
3012 PRUint32
*aUTF16Offset
,
3013 PangoGlyphUnit aOverrideSpaceWidth
)
3015 PRUint32 utf16Offset
= *aUTF16Offset
;
3016 PRUint32 textRunLength
= aTextRun
->GetLength();
3017 const PRUint32 appUnitsPerDevUnit
= aTextRun
->GetAppUnitsPerDevUnit();
3018 const gfxTextRun::CompressedGlyph
*charGlyphs
= aTextRun
->GetCharacterGlyphs();
3020 // Override the width of a space, but only for spaces that aren't
3021 // clustered with something else (like a freestanding diacritical mark)
3022 PangoGlyphUnit width
= aGlyphs
[0].geometry
.width
;
3023 if (aOverrideSpaceWidth
&& aUTF8
[0] == ' ' &&
3024 (utf16Offset
+ 1 == textRunLength
||
3025 charGlyphs
[utf16Offset
].IsClusterStart())) {
3026 width
= aOverrideSpaceWidth
;
3028 PRInt32 advance
= ConvertPangoToAppUnits(width
, appUnitsPerDevUnit
);
3030 gfxTextRun::CompressedGlyph g
;
3031 PRBool atClusterStart
= aTextRun
->IsClusterStart(utf16Offset
);
3032 // See if we fit in the compressed area.
3033 if (aGlyphCount
== 1 && advance
>= 0 && atClusterStart
&&
3034 aGlyphs
[0].geometry
.x_offset
== 0 &&
3035 aGlyphs
[0].geometry
.y_offset
== 0 &&
3036 !IS_EMPTY_GLYPH(aGlyphs
[0].glyph
) &&
3037 gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance
) &&
3038 gfxTextRun::CompressedGlyph::IsSimpleGlyphID(aGlyphs
[0].glyph
)) {
3039 aTextRun
->SetSimpleGlyph(utf16Offset
,
3040 g
.SetSimpleGlyph(advance
, aGlyphs
[0].glyph
));
3042 nsAutoTArray
<gfxTextRun::DetailedGlyph
,10> detailedGlyphs
;
3043 if (!detailedGlyphs
.AppendElements(aGlyphCount
))
3044 return NS_ERROR_OUT_OF_MEMORY
;
3046 PRInt32 direction
= aTextRun
->IsRightToLeft() ? -1 : 1;
3047 PRUint32 pangoIndex
= direction
> 0 ? 0 : aGlyphCount
- 1;
3048 PRUint32 detailedIndex
= 0;
3049 for (PRUint32 i
= 0; i
< aGlyphCount
; ++i
) {
3050 const PangoGlyphInfo
&glyph
= aGlyphs
[pangoIndex
];
3051 pangoIndex
+= direction
;
3052 // The zero width characters return empty glyph ID at
3053 // shaping; we should skip these.
3054 if (IS_EMPTY_GLYPH(glyph
.glyph
))
3057 gfxTextRun::DetailedGlyph
*details
= &detailedGlyphs
[detailedIndex
];
3060 details
->mGlyphID
= glyph
.glyph
;
3061 NS_ASSERTION(details
->mGlyphID
== glyph
.glyph
,
3062 "Seriously weird glyph ID detected!");
3064 ConvertPangoToAppUnits(glyph
.geometry
.width
,
3065 appUnitsPerDevUnit
);
3067 float(glyph
.geometry
.x_offset
)*appUnitsPerDevUnit
/PANGO_SCALE
;
3069 float(glyph
.geometry
.y_offset
)*appUnitsPerDevUnit
/PANGO_SCALE
;
3071 g
.SetComplex(atClusterStart
, PR_TRUE
, detailedIndex
);
3072 aTextRun
->SetGlyphs(utf16Offset
, g
, detailedGlyphs
.Elements());
3075 // Check for ligatures and set *aUTF16Offset.
3076 const gchar
*p
= aUTF8
;
3077 const gchar
*end
= aUTF8
+ aUTF8Length
;
3079 // Skip the CompressedGlyph that we have added, but check if the
3080 // character was supposed to be ignored. If it's supposed to be ignored,
3081 // overwrite the textrun entry with an invisible missing-glyph.
3082 gunichar ch
= g_utf8_get_char(p
);
3083 NS_ASSERTION(!IS_SURROGATE(ch
), "surrogates should not appear in UTF8");
3084 if (ch
>= 0x10000) {
3088 NS_ASSERTION(!gfxFontGroup::IsInvalidChar(PRUnichar(ch
)),
3089 "Invalid character detected");
3092 // We produced this UTF8 so we don't need to worry about malformed stuff
3093 p
= g_utf8_next_char(p
);
3097 if (utf16Offset
>= textRunLength
) {
3098 NS_ERROR("Someone has added too many glyphs!");
3099 return NS_ERROR_FAILURE
;
3102 g
.SetComplex(aTextRun
->IsClusterStart(utf16Offset
), PR_FALSE
, 0);
3103 aTextRun
->SetGlyphs(utf16Offset
, g
, nsnull
);
3105 *aUTF16Offset
= utf16Offset
;
3110 gfxPangoFontGroup::SetGlyphs(gfxTextRun
*aTextRun
,
3111 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
3112 PRUint32
*aUTF16Offset
, PangoGlyphString
*aGlyphs
,
3113 PangoGlyphUnit aOverrideSpaceWidth
,
3114 PRBool aAbortOnMissingGlyph
)
3116 gint numGlyphs
= aGlyphs
->num_glyphs
;
3117 PangoGlyphInfo
*glyphs
= aGlyphs
->glyphs
;
3118 const gint
*logClusters
= aGlyphs
->log_clusters
;
3119 // We cannot make any assumptions about the order of glyph clusters
3120 // provided by pango_shape (see 375864), so we work through the UTF8 text
3121 // and process the glyph clusters in logical order.
3123 // logGlyphs is like an inverse of logClusters. For each UTF8 byte:
3124 // >= 0 indicates that the byte is first in a cluster and
3125 // gives the position of the starting glyph for the cluster.
3126 // -1 indicates that the byte does not start a cluster.
3127 nsAutoTArray
<gint
,2000> logGlyphs
;
3128 if (!logGlyphs
.AppendElements(aUTF8Length
+ 1))
3129 return NS_ERROR_OUT_OF_MEMORY
;
3130 PRUint32 utf8Index
= 0;
3131 for(; utf8Index
< aUTF8Length
; ++utf8Index
)
3132 logGlyphs
[utf8Index
] = -1;
3133 logGlyphs
[aUTF8Length
] = numGlyphs
;
3135 gint lastCluster
= -1; // != utf8Index
3136 for (gint glyphIndex
= 0; glyphIndex
< numGlyphs
; ++glyphIndex
) {
3137 gint thisCluster
= logClusters
[glyphIndex
];
3138 if (thisCluster
!= lastCluster
) {
3139 lastCluster
= thisCluster
;
3140 NS_ASSERTION(0 <= thisCluster
&& thisCluster
< gint(aUTF8Length
),
3141 "garbage from pango_shape - this is bad");
3142 logGlyphs
[thisCluster
] = glyphIndex
;
3146 PRUint32 utf16Offset
= *aUTF16Offset
;
3147 PRUint32 textRunLength
= aTextRun
->GetLength();
3149 // The next glyph cluster in logical order.
3150 gint nextGlyphClusterStart
= logGlyphs
[utf8Index
];
3151 NS_ASSERTION(nextGlyphClusterStart
>= 0, "No glyphs! - NUL in string?");
3152 while (utf8Index
< aUTF8Length
) {
3153 if (utf16Offset
>= textRunLength
) {
3154 NS_ERROR("Someone has added too many glyphs!");
3155 return NS_ERROR_FAILURE
;
3157 gint glyphClusterStart
= nextGlyphClusterStart
;
3158 // Find the utf8 text associated with this glyph cluster.
3159 PRUint32 clusterUTF8Start
= utf8Index
;
3160 // Check we are consistent with pango_break data.
3161 NS_ASSERTION(aTextRun
->GetCharacterGlyphs()->IsClusterStart(),
3162 "Glyph cluster not aligned on character cluster.");
3165 nextGlyphClusterStart
= logGlyphs
[utf8Index
];
3166 } while (nextGlyphClusterStart
< 0);
3167 const gchar
*clusterUTF8
= &aUTF8
[clusterUTF8Start
];
3168 PRUint32 clusterUTF8Length
= utf8Index
- clusterUTF8Start
;
3170 PRBool haveMissingGlyph
= PR_FALSE
;
3171 gint glyphIndex
= glyphClusterStart
;
3173 // It's now unncecessary to do NUL handling here.
3175 if (IS_MISSING_GLYPH(glyphs
[glyphIndex
].glyph
)) {
3176 // Does pango ever provide more than one glyph in the
3177 // cluster if there is a missing glyph?
3179 haveMissingGlyph
= PR_TRUE
;
3182 } while (glyphIndex
< numGlyphs
&&
3183 logClusters
[glyphIndex
] == gint(clusterUTF8Start
));
3185 if (haveMissingGlyph
&& aAbortOnMissingGlyph
)
3186 return NS_ERROR_FAILURE
;
3189 if (haveMissingGlyph
) {
3190 rv
= SetMissingGlyphs(aTextRun
, clusterUTF8
, clusterUTF8Length
,
3193 rv
= SetGlyphsForCharacterGroup(&glyphs
[glyphClusterStart
],
3194 glyphIndex
- glyphClusterStart
,
3196 clusterUTF8
, clusterUTF8Length
,
3197 &utf16Offset
, aOverrideSpaceWidth
);
3199 NS_ENSURE_SUCCESS(rv
,rv
);
3201 *aUTF16Offset
= utf16Offset
;
3206 gfxPangoFontGroup::SetMissingGlyphs(gfxTextRun
*aTextRun
,
3207 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
3208 PRUint32
*aUTF16Offset
)
3210 PRUint32 utf16Offset
= *aUTF16Offset
;
3211 PRUint32 textRunLength
= aTextRun
->GetLength();
3212 for (PRUint32 index
= 0; index
< aUTF8Length
;) {
3213 if (utf16Offset
>= textRunLength
) {
3214 NS_ERROR("Someone has added too many glyphs!");
3217 gunichar ch
= g_utf8_get_char(aUTF8
+ index
);
3218 aTextRun
->SetMissingGlyph(utf16Offset
, ch
);
3221 NS_ASSERTION(!IS_SURROGATE(ch
), "surrogates should not appear in UTF8");
3224 // We produced this UTF8 so we don't need to worry about malformed stuff
3225 index
= g_utf8_next_char(aUTF8
+ index
) - aUTF8
;
3228 *aUTF16Offset
= utf16Offset
;
3232 #if defined(ENABLE_FAST_PATH_8BIT) || defined(ENABLE_FAST_PATH_ALWAYS)
3234 gfxPangoFontGroup::CreateGlyphRunsFast(gfxTextRun
*aTextRun
,
3235 const gchar
*aUTF8
, PRUint32 aUTF8Length
)
3237 const gchar
*p
= aUTF8
;
3238 PangoFont
*pangofont
= GetBasePangoFont();
3239 PangoFcFont
*fcfont
= PANGO_FC_FONT (pangofont
);
3240 gfxFcFont
*gfxFont
= gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(pangofont
));
3241 PRUint32 utf16Offset
= 0;
3242 gfxTextRun::CompressedGlyph g
;
3243 const PRUint32 appUnitsPerDevUnit
= aTextRun
->GetAppUnitsPerDevUnit();
3245 aTextRun
->AddGlyphRun(gfxFont
, 0);
3247 while (p
< aUTF8
+ aUTF8Length
) {
3248 // glib-2.12.9: "If p does not point to a valid UTF-8 encoded
3249 // character, results are undefined." so it is not easy to assert that
3250 // aUTF8 in fact points to UTF8 data but asserting
3251 // g_unichar_validate(ch) may be mildly useful.
3252 gunichar ch
= g_utf8_get_char(p
);
3253 p
= g_utf8_next_char(p
);
3256 // treat this null byte as a missing glyph. Pango
3257 // doesn't create glyphs for these, not even missing-glyphs.
3258 aTextRun
->SetMissingGlyph(utf16Offset
, 0);
3260 NS_ASSERTION(!IsInvalidChar(ch
), "Invalid char detected");
3261 FT_UInt glyph
= pango_fc_font_get_glyph (fcfont
, ch
);
3262 if (!glyph
) // character not in font,
3263 return NS_ERROR_FAILURE
; // fallback to CreateGlyphRunsItemizing
3265 cairo_text_extents_t extents
;
3266 gfxFont
->GetGlyphExtents(glyph
, &extents
);
3268 PRInt32 advance
= NS_lround(extents
.x_advance
* appUnitsPerDevUnit
);
3270 gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance
) &&
3271 gfxTextRun::CompressedGlyph::IsSimpleGlyphID(glyph
)) {
3272 aTextRun
->SetSimpleGlyph(utf16Offset
,
3273 g
.SetSimpleGlyph(advance
, glyph
));
3275 gfxTextRun::DetailedGlyph details
;
3276 details
.mGlyphID
= glyph
;
3277 NS_ASSERTION(details
.mGlyphID
== glyph
,
3278 "Seriously weird glyph ID detected!");
3279 details
.mAdvance
= advance
;
3280 details
.mXOffset
= 0;
3281 details
.mYOffset
= 0;
3282 g
.SetComplex(aTextRun
->IsClusterStart(utf16Offset
), PR_TRUE
, 1);
3283 aTextRun
->SetGlyphs(utf16Offset
, g
, &details
);
3286 NS_ASSERTION(!IS_SURROGATE(ch
), "Surrogates shouldn't appear in UTF8");
3287 if (ch
>= 0x10000) {
3288 // This character is a surrogate pair in UTF16
3300 gfxPangoFontGroup::CreateGlyphRunsItemizing(gfxTextRun
*aTextRun
,
3301 const gchar
*aUTF8
, PRUint32 aUTF8Length
,
3302 PRUint32 aUTF8HeaderLen
)
3304 // This font group and gfxPangoFontMap are recorded on the PangoContext
3305 // passed to pango_itemize_with_base_dir().
3307 // pango_itemize_with_base_dir() divides the string into substrings for
3308 // each language, and queries gfxPangoFontMap::load_fontset() to provide
3309 // ordered lists of fonts for each language. gfxPangoFontMap passes the
3310 // request back to this font group, which returns a gfxFcPangoFontSet
3311 // handling the font sorting/selection.
3313 // For each character, pango_itemize_with_base_dir searches through these
3314 // lists of fonts for a font with support for the character. The
3315 // PangoItems returned represent substrings (or runs) of consectutive
3316 // characters to be shaped with the same PangoFont and having the same
3319 // The PangoFonts in the PangoItems are from the gfxPangoFontMap and so
3320 // each have a gfxFont. This gfxFont represents the same face as the
3321 // PangoFont and so can render the same glyphs in the same way as
3322 // pango_shape measures.
3324 PangoContext
*context
= GetPangoContext();
3325 // we should set this to null if we don't have a text language from the page...
3326 // except that we almost always have something...
3327 pango_context_set_language(context
, mPangoLanguage
);
3328 SetFontGroup(context
, this);
3330 PangoDirection dir
= aTextRun
->IsRightToLeft() ? PANGO_DIRECTION_RTL
: PANGO_DIRECTION_LTR
;
3331 GList
*items
= pango_itemize_with_base_dir(context
, dir
, aUTF8
, 0, aUTF8Length
, nsnull
, nsnull
);
3333 PRUint32 utf16Offset
= 0;
3335 PRBool isRTL
= aTextRun
->IsRightToLeft();
3338 PangoGlyphString
*glyphString
= pango_glyph_string_new();
3342 for (; pos
&& pos
->data
; pos
= pos
->next
) {
3343 PangoItem
*item
= (PangoItem
*)pos
->data
;
3344 NS_ASSERTION(isRTL
== item
->analysis
.level
% 2, "RTL assumption mismatch");
3346 PRUint32 offset
= item
->offset
;
3347 PRUint32 length
= item
->length
;
3348 if (offset
< aUTF8HeaderLen
) {
3349 if (offset
+ length
<= aUTF8HeaderLen
)
3352 length
-= aUTF8HeaderLen
- offset
;
3353 offset
= aUTF8HeaderLen
;
3357 gfxPangoFcFont::GfxFont(GFX_PANGO_FC_FONT(item
->analysis
.font
));
3359 nsresult rv
= aTextRun
->AddGlyphRun(font
, utf16Offset
);
3360 if (NS_FAILED(rv
)) {
3361 NS_ERROR("AddGlyphRun Failed");
3365 PRUint32 spaceWidth
=
3366 moz_pango_units_from_double(font
->GetMetrics().spaceWidth
);
3368 const gchar
*p
= aUTF8
+ offset
;
3369 const gchar
*end
= p
+ length
;
3372 aTextRun
->SetMissingGlyph(utf16Offset
, 0);
3378 // It's necessary to loop over pango_shape as it treats
3379 // NULs as string terminators
3380 const gchar
*text
= p
;
3383 } while(p
< end
&& *p
!= 0);
3384 gint len
= p
- text
;
3386 pango_shape(text
, len
, &item
->analysis
, glyphString
);
3387 SetupClusterBoundaries(aTextRun
, text
, len
, utf16Offset
, &item
->analysis
);
3388 SetGlyphs(aTextRun
, text
, len
, &utf16Offset
, glyphString
, spaceWidth
, PR_FALSE
);
3394 pango_glyph_string_free(glyphString
);
3396 for (pos
= items
; pos
; pos
= pos
->next
)
3397 pango_item_free((PangoItem
*)pos
->data
);
3402 g_object_unref(context
);
3407 GuessPangoLanguage(const nsACString
& aLangGroup
)
3409 // See if the lang group needs to be translated from Mozilla's
3410 // internal mapping into fontconfig's
3412 gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup
, &lang
);
3417 return pango_language_from_string(lang
.get());
3420 #ifdef MOZ_WIDGET_GTK2
3421 /***************************************************************************
3423 * This function must be last in the file because it uses the system cairo
3424 * library. Above this point the cairo library used is the tree cairo if
3429 // Tree cairo symbols have different names. Disable their activation through
3430 // preprocessor macros.
3431 #undef cairo_ft_font_options_substitute
3433 // The system cairo functions are not declared because the include paths cause
3434 // the gdk headers to pick up the tree cairo.h.
3436 NS_VISIBILITY_DEFAULT
void
3437 cairo_ft_font_options_substitute (const cairo_font_options_t
*options
,
3438 FcPattern
*pattern
);
3443 ApplyGdkScreenFontOptions(FcPattern
*aPattern
)
3445 const cairo_font_options_t
*options
=
3446 gdk_screen_get_font_options(gdk_screen_get_default());
3448 cairo_ft_font_options_substitute(options
, aPattern
);
3451 #endif // MOZ_WIDGET_GTK2