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.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #if defined(MOZ_WIDGET_GTK2)
38 #include "gfxPlatformGtk.h"
39 #define gfxToolkitPlatform gfxPlatformGtk
40 #elif defined(MOZ_WIDGET_QT)
41 #include "gfxQtPlatform.h"
42 #include <qfontinfo.h>
43 #define gfxToolkitPlatform gfxQtPlatform
46 #include "gfxFT2Fonts.h"
49 #include <freetype/tttables.h>
50 #include "gfxFontUtils.h"
56 FontEntry::FontEntry(const FontEntry
& aFontEntry
) :
57 gfxFontEntry(aFontEntry
)
59 if (aFontEntry
.mFontFace
)
60 mFontFace
= cairo_font_face_reference(aFontEntry
.mFontFace
);
65 FontEntry::~FontEntry()
68 cairo_font_face_destroy(mFontFace
);
74 FTFontDestroyFunc(void *data
)
76 FT_Face face
= (FT_Face
)data
;
81 gfxFT2Font::GetFontEntry()
83 return static_cast<FontEntry
*> (mFontEntry
.get());
87 FontEntry::CairoFontFace()
89 static cairo_user_data_key_t key
;
93 FT_New_Face(gfxToolkitPlatform::GetPlatform()->GetFTLibrary(), mFilename
.get(), mFTFontIndex
, &face
);
94 mFontFace
= cairo_ft_font_face_create_for_ft_face(face
, 0);
95 cairo_font_face_set_user_data(mFontFace
, &key
, face
, FTFontDestroyFunc
);
101 FontFamily::FindFontEntry(const gfxFontStyle
& aFontStyle
)
103 PRBool italic
= (aFontStyle
.style
& (FONT_STYLE_ITALIC
| FONT_STYLE_OBLIQUE
)) != 0;
105 FontEntry
*weightList
[10] = { 0 };
106 for (PRUint32 j
= 0; j
< 2; j
++) {
107 PRBool matchesSomething
= PR_FALSE
;
108 // build up an array of weights that match the italicness we're looking for
109 for (PRUint32 i
= 0; i
< mFaces
.Length(); i
++) {
110 FontEntry
*fe
= mFaces
[i
];
111 const PRUint8 weight
= (fe
->mWeight
/ 100);
112 if (fe
->mItalic
== italic
) {
113 weightList
[weight
] = fe
;
114 matchesSomething
= PR_TRUE
;
117 if (matchesSomething
)
122 PRInt8 baseWeight
, weightDistance
;
123 aFontStyle
.ComputeWeightAndOffset(&baseWeight
, &weightDistance
);
125 // 500 isn't quite bold so we want to treat it as 400 if we don't
127 if (baseWeight
== 5 && weightDistance
== 0) {
128 // If we have a 500 weight then use it
130 return weightList
[5];
132 // Otherwise treat as 400
136 PRInt8 matchBaseWeight
= 0;
137 PRInt8 direction
= (baseWeight
> 5) ? 1 : -1;
138 for (PRInt8 i
= baseWeight
; ; i
+= direction
) {
144 // if we've reached one side without finding a font,
145 // go the other direction until we find a match
146 if (i
== 1 || i
== 9)
147 direction
= -direction
;
151 const PRInt8 absDistance
= abs(weightDistance
);
152 direction
= (weightDistance
>= 0) ? 1 : -1;
153 for (PRInt8 i
= matchBaseWeight
, k
= 0; i
< 10 && i
> 0; i
+= direction
) {
155 matchFE
= weightList
[i
];
163 matchFE
= weightList
[matchBaseWeight
];
165 NS_ASSERTION(matchFE
, "we should always be able to return something here");
176 gfxFT2FontGroup::FontCallback(const nsAString
& fontName
,
177 const nsACString
& genericName
,
180 nsStringArray
*sa
= static_cast<nsStringArray
*>(closure
);
182 if (!fontName
.IsEmpty() && sa
->IndexOf(fontName
) < 0) {
183 sa
->AppendString(fontName
);
185 printf(" - %s\n", NS_ConvertUTF16toUTF8(fontName
).get());
193 * Look up the font in the gfxFont cache. If we don't find it, create one.
194 * In either case, add a ref, append it to the aFonts array, and return it ---
195 * except for OOM in which case we do nothing and return null.
197 static already_AddRefed
<gfxFT2Font
>
198 GetOrMakeFont(const nsAString
& aName
, const gfxFontStyle
*aStyle
)
200 nsRefPtr
<gfxFont
> font
= gfxFontCache::GetCache()->Lookup(aName
, aStyle
);
202 FontEntry
*fe
= gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName
, *aStyle
);
204 printf("Failed to find font entry for %s\n", NS_ConvertUTF16toUTF8(aName
).get());
208 font
= new gfxFT2Font(fe
, aStyle
);
211 gfxFontCache::GetCache()->AddNew(font
);
215 return static_cast<gfxFT2Font
*>(f
);
219 gfxFT2FontGroup::gfxFT2FontGroup(const nsAString
& families
,
220 const gfxFontStyle
*aStyle
)
221 : gfxFontGroup(families
, aStyle
)
224 printf("Looking for %s\n", NS_ConvertUTF16toUTF8(families
).get());
226 nsStringArray familyArray
;
227 ForEachFont(FontCallback
, &familyArray
);
229 if (familyArray
.Count() == 0) {
230 nsAutoString prefFamilies
;
231 gfxToolkitPlatform::GetPlatform()->GetPrefFonts(aStyle
->langGroup
.get(), prefFamilies
, nsnull
);
232 if (!prefFamilies
.IsEmpty()) {
233 ForEachFont(prefFamilies
, aStyle
->langGroup
, FontCallback
, &familyArray
);
236 #if defined(MOZ_WIDGET_QT) /* FIXME DFB */
237 if (familyArray
.Count() == 0) {
238 printf("failde to find a font. sadface\n");
239 // We want to get rid of this entirely at some point, but first we need real lists of fonts.
241 QFontInfo
fi (defaultFont
);
242 familyArray
.AppendString(nsDependentString(static_cast<const PRUnichar
*>(fi
.family().utf16())));
246 for (int i
= 0; i
< familyArray
.Count(); i
++) {
247 nsRefPtr
<gfxFT2Font
> font
= GetOrMakeFont(*familyArray
[i
], &mStyle
);
249 mFonts
.AppendElement(font
);
254 gfxFT2FontGroup::~gfxFT2FontGroup()
259 gfxFT2FontGroup::Copy(const gfxFontStyle
*aStyle
)
261 return new gfxFT2FontGroup(mFamilies
, aStyle
);
265 * We use this to append an LTR or RTL Override character to the start of the
266 * string. This forces Pango to honour our direction even if there are neutral
267 * characters in the string.
269 static PRInt32
AppendDirectionalIndicatorUTF8(PRBool aIsRTL
, nsACString
& aString
)
271 static const PRUnichar overrides
[2][2] = { { 0x202d, 0 }, { 0x202e, 0 }}; // LRO, RLO
272 AppendUTF16toUTF8(overrides
[aIsRTL
], aString
);
273 return 3; // both overrides map to 3 bytes in UTF8
276 gfxTextRun
*gfxFT2FontGroup::MakeTextRun(const PRUnichar
* aString
, PRUint32 aLength
,
277 const Parameters
* aParams
, PRUint32 aFlags
)
279 gfxTextRun
*textRun
= gfxTextRun::Create(aParams
, aString
, aLength
, this, aFlags
);
283 textRun
->RecordSurrogates(aString
);
285 mString
.Assign(nsDependentSubstring(aString
, aString
+ aLength
));
287 InitTextRun(textRun
);
289 textRun
->FetchGlyphExtents(aParams
->mContext
);
294 gfxTextRun
*gfxFT2FontGroup::MakeTextRun(const PRUint8
*aString
, PRUint32 aLength
,
295 const Parameters
*aParams
, PRUint32 aFlags
)
297 NS_ASSERTION(aFlags
& TEXT_IS_8BIT
, "8bit should have been set");
298 gfxTextRun
*textRun
= gfxTextRun::Create(aParams
, aString
, aLength
, this, aFlags
);
302 const char *chars
= reinterpret_cast<const char *>(aString
);
304 mString
.Assign(NS_ConvertASCIItoUTF16(nsDependentCSubstring(chars
, chars
+ aLength
)));
306 InitTextRun(textRun
);
308 textRun
->FetchGlyphExtents(aParams
->mContext
);
313 void gfxFT2FontGroup::InitTextRun(gfxTextRun
*aTextRun
)
315 CreateGlyphRunsFT(aTextRun
);
319 // Helper function to return the leading UTF-8 character in a char pointer
320 // as 32bit number. Also sets the length of the current character (i.e. the
321 // offset to the next one) in the second argument
322 PRUint32
getUTF8CharAndNext(const PRUint8
*aString
, PRUint8
*aLength
)
325 if (aString
[0] < 0x80) { // normal 7bit ASCII char
328 if ((aString
[0] >> 5) == 6) { // two leading ones -> two bytes
330 return ((aString
[0] & 0x1F) << 6) + (aString
[1] & 0x3F);
332 if ((aString
[0] >> 4) == 14) { // three leading ones -> three bytes
334 return ((aString
[0] & 0x0F) << 12) + ((aString
[1] & 0x3F) << 6) +
337 if ((aString
[0] >> 4) == 15) { // four leading ones -> four bytes
339 return ((aString
[0] & 0x07) << 18) + ((aString
[1] & 0x3F) << 12) +
340 ((aString
[2] & 0x3F) << 6) + (aString
[3] & 0x3F);
353 HasCharacter(gfxFT2Font
*aFont
, PRUint32 ch
)
355 if (aFont
->GetFontEntry()->mCharacterMap
.test(ch
))
358 // XXX move this lock way way out
359 FT_Face face
= cairo_ft_scaled_font_lock_face(aFont
->CairoScaledFont());
360 FT_UInt gid
= FT_Get_Char_Index(face
, ch
);
361 cairo_ft_scaled_font_unlock_face(aFont
->CairoScaledFont());
364 aFont
->GetFontEntry()->mCharacterMap
.set(ch
);
372 gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray
<>& foo
, PRUint32 ch
)
374 for (int i
= 0; i
< aGroup
->FontListLength(); i
++) {
375 nsRefPtr
<gfxFT2Font
> font
= aGroup
->GetFontAt(i
);
376 if (HasCharacter(font
, ch
))
384 gfxFT2FontGroup::FindFontForChar(PRUint32 ch
, PRUint32 prevCh
, PRUint32 nextCh
, gfxFT2Font
*aFont
)
386 gfxFT2Font
*selectedFont
;
388 // if this character or the next one is a joiner use the
389 // same font as the previous range if we can
390 if (gfxFontUtils::IsJoiner(ch
) || gfxFontUtils::IsJoiner(prevCh
) || gfxFontUtils::IsJoiner(nextCh
)) {
391 if (aFont
&& HasCharacter(aFont
, ch
))
395 for (PRUint32 i
= 0; i
< FontListLength(); i
++) {
396 nsRefPtr
<gfxFT2Font
> font
= GetFontAt(i
);
397 if (HasCharacter(font
, ch
))
403 // check the list of fonts
404 selectedFont
= WhichFontSupportsChar(mGroup
->GetFontList(), ch
);
407 // don't look in other fonts if the character is in a Private Use Area
408 if ((ch
>= 0xE000 && ch
<= 0xF8FF) ||
409 (ch
>= 0xF0000 && ch
<= 0x10FFFD))
412 // check out the style's language group
414 nsAutoTArray
<nsRefPtr
<FontEntry
>, 5> fonts
;
415 this->GetPrefFonts(mGroup
->GetStyle()->langGroup
.get(), fonts
);
416 selectedFont
= WhichFontSupportsChar(fonts
, ch
);
419 // otherwise search prefs
421 /* first check with the script properties to see what they think */
423 PRUint32 unicodeRange
= FindCharUnicodeRange(ch
);
425 /* special case CJK */
426 if (unicodeRange
== kRangeSetCJK
) {
427 if (PR_LOG_TEST(gFontLog
, PR_LOG_DEBUG
))
428 PR_LOG(gFontLog
, PR_LOG_DEBUG
, (" - Trying to find fonts for: CJK"));
430 nsAutoTArray
<nsRefPtr
<FontEntry
>, 15> fonts
;
431 this->GetCJKPrefFonts(fonts
);
432 selectedFont
= WhichFontSupportsChar(fonts
, ch
);
434 const char *langGroup
= LangGroupFromUnicodeRange(unicodeRange
);
436 PR_LOG(gFontLog
, PR_LOG_DEBUG
, (" - Trying to find fonts for: %s", langGroup
));
438 nsAutoTArray
<nsRefPtr
<FontEntry
>, 5> fonts
;
439 this->GetPrefFonts(langGroup
, fonts
);
440 selectedFont
= WhichFontSupportsChar(fonts
, ch
);
446 // before searching for something else check the font used for the previous character
447 if (!selectedFont
&& aFont
&& HasCharacter(aFont
, ch
))
448 selectedFont
= aFont
;
450 // otherwise look for other stuff
452 PR_LOG(gFontLog
, PR_LOG_DEBUG
, (" - Looking for best match"));
454 nsRefPtr
<gfxWindowsFont
> refFont
= mGroup
->GetFontAt(0);
455 gfxWindowsPlatform
*platform
= gfxWindowsPlatform::GetPlatform();
456 selectedFont
= platform
->FindFontForChar(ch
, refFont
);
464 gfxFT2FontGroup::ComputeRanges()
466 const PRUnichar
*str
= mString
.get();
467 PRUint32 len
= mString
.Length();
472 for (PRUint32 i
= 0; i
< len
; i
++) {
473 const PRUint32 origI
= i
; // save off incase we increase for surrogate
474 PRUint32 ch
= str
[i
];
475 if ((i
+1 < len
) && NS_IS_HIGH_SURROGATE(ch
) && NS_IS_LOW_SURROGATE(str
[i
+1])) {
477 ch
= SURROGATE_TO_UCS4(ch
, str
[i
]);
483 if ((i
+2 < len
) && NS_IS_HIGH_SURROGATE(ch
) && NS_IS_LOW_SURROGATE(str
[i
+2]))
484 nextCh
= SURROGATE_TO_UCS4(nextCh
, str
[i
+2]);
486 gfxFT2Font
*fe
= FindFontForChar(ch
,
489 (mRanges
.Length() == 0) ? nsnull
: mRanges
[mRanges
.Length() - 1].font
);
493 if (mRanges
.Length() == 0) {
496 mRanges
.AppendElement(r
);
498 TextRange
& prevRange
= mRanges
[mRanges
.Length() - 1];
499 if (prevRange
.font
!= fe
) {
500 // close out the previous range
501 prevRange
.end
= origI
;
503 TextRange
r(origI
, i
+1);
505 mRanges
.AppendElement(r
);
509 mRanges
[mRanges
.Length()-1].end
= len
;
511 PRUint32 nranges
= mRanges
.Length();
515 void gfxFT2FontGroup::CreateGlyphRunsFT(gfxTextRun
*aTextRun
)
519 const PRUnichar
*strStart
= mString
.get();
520 for (PRUint32 i
= 0; i
< mRanges
.Length(); ++i
) {
521 const TextRange
& range
= mRanges
[i
];
522 const PRUnichar
*rangeString
= strStart
+ range
.start
;
523 PRUint32 rangeLength
= range
.Length();
525 gfxFT2Font
*font
= range
.font
? range
.font
.get() : GetFontAt(0);
526 AddRange(aTextRun
, font
, rangeString
, rangeLength
);
532 gfxFT2FontGroup::AddRange(gfxTextRun
*aTextRun
, gfxFT2Font
*font
, const PRUnichar
*str
, PRUint32 len
)
534 const PRUint32 appUnitsPerDevUnit
= aTextRun
->GetAppUnitsPerDevUnit();
535 // we'll pass this in/figure it out dynamically, but at this point there can be only one face.
536 FT_Face face
= cairo_ft_scaled_font_lock_face(font
->CairoScaledFont());
538 gfxTextRun::CompressedGlyph g
;
540 aTextRun
->AddGlyphRun(font
, 0);
541 for (PRUint32 i
= 0; i
< len
; i
++) {
542 PRUint32 ch
= str
[i
];
545 // treat this null byte as a missing glyph, don't create a glyph for it
546 aTextRun
->SetMissingGlyph(i
, 0);
550 NS_ASSERTION(!IsInvalidChar(ch
), "Invalid char detected");
551 FT_UInt gid
= FT_Get_Char_Index(face
, ch
); // find the glyph id
554 if (gid
== font
->GetSpaceGlyph()) {
555 advance
= (int)(font
->GetMetrics().spaceWidth
* appUnitsPerDevUnit
);
556 } else if (gid
== 0) {
557 advance
= -1; // trigger the missing glyphs case below
559 // find next character and its glyph -- in case they exist
560 // and exist in the current font face -- to compute kerning
563 FT_Pos lsbDeltaNext
= 0;
565 if (FT_HAS_KERNING(face
) && i
+ 1 < len
) {
568 gidNext
= FT_Get_Char_Index(face
, chNext
);
569 if (gidNext
&& gidNext
!= font
->GetSpaceGlyph()) {
570 FT_Load_Glyph(face
, gidNext
, FT_LOAD_DEFAULT
);
571 lsbDeltaNext
= face
->glyph
->lsb_delta
;
576 // now load the current glyph
577 FT_Load_Glyph(face
, gid
, FT_LOAD_DEFAULT
); // load glyph into the slot
578 advance
= face
->glyph
->advance
.x
;
580 // now add kerning to the current glyph's advance
581 if (chNext
&& gidNext
) {
582 FT_Vector kerning
; kerning
.x
= 0;
583 FT_Get_Kerning(face
, gid
, gidNext
, FT_KERNING_DEFAULT
, &kerning
);
584 advance
+= kerning
.x
;
585 if (face
->glyph
->rsb_delta
- lsbDeltaNext
>= 32) {
587 } else if (face
->glyph
->rsb_delta
- lsbDeltaNext
< -32) {
592 // now apply unit conversion and scaling
593 advance
= (advance
>> 6) * appUnitsPerDevUnit
;
595 #ifdef DEBUG_thebes_2
596 printf(" gid=%d, advance=%d (%s)\n", gid
, advance
,
597 NS_LossyConvertUTF16toASCII(font
->GetName()).get());
601 gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance
) &&
602 gfxTextRun::CompressedGlyph::IsSimpleGlyphID(gid
)) {
603 aTextRun
->SetSimpleGlyph(i
, g
.SetSimpleGlyph(advance
, gid
));
604 } else if (gid
== 0) {
605 // gid = 0 only happens when the glyph is missing from the font
606 aTextRun
->SetMissingGlyph(i
, ch
);
608 gfxTextRun::DetailedGlyph details
;
609 details
.mGlyphID
= gid
;
610 NS_ASSERTION(details
.mGlyphID
== gid
, "Seriously weird glyph ID detected!");
611 details
.mAdvance
= advance
;
612 details
.mXOffset
= 0;
613 details
.mYOffset
= 0;
614 g
.SetComplex(aTextRun
->IsClusterStart(i
), PR_TRUE
, 1);
615 aTextRun
->SetGlyphs(i
, g
, &details
);
619 cairo_ft_scaled_font_unlock_face(font
->CairoScaledFont());
625 gfxFT2Font::gfxFT2Font(FontEntry
*aFontEntry
,
626 const gfxFontStyle
*aFontStyle
)
627 : gfxFont(aFontEntry
, aFontStyle
),
629 mHasSpaceGlyph(PR_FALSE
),
631 mHasMetrics(PR_FALSE
),
634 mFontEntry
= aFontEntry
;
635 NS_ASSERTION(mFontEntry
, "Unable to find font entry for font. Something is whack.");
638 gfxFT2Font::~gfxFT2Font()
641 cairo_scaled_font_destroy(mScaledFont
);
642 mScaledFont
= nsnull
;
646 // rounding and truncation functions for a Freetype floating point number
647 // (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
648 // part and low 6 bits for the fractional part.
649 #define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
650 #define MOZ_FT_TRUNC(x) ((x) >> 6)
651 #define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
652 MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
654 const gfxFont::Metrics
&
655 gfxFT2Font::GetMetrics()
660 mMetrics
.emHeight
= GetStyle()->size
;
662 FT_Face face
= cairo_ft_scaled_font_lock_face(CairoScaledFont());
665 // Abort here already, otherwise we crash in the following
666 // this can happen if the font-size requested is zero.
667 // The metrics will be incomplete, but then we don't care.
671 mMetrics
.emHeight
= GetStyle()->size
;
673 FT_UInt gid
; // glyph ID
675 const double emUnit
= 1.0 * face
->units_per_EM
;
676 const double xScale
= face
->size
->metrics
.x_ppem
/ emUnit
;
677 const double yScale
= face
->size
->metrics
.y_ppem
/ emUnit
;
679 // properties of space
680 gid
= FT_Get_Char_Index(face
, ' ');
682 FT_Load_Glyph(face
, gid
, FT_LOAD_DEFAULT
);
683 // face->glyph->metrics.width doesn't work for spaces, use advance.x instead
684 mMetrics
.spaceWidth
= face
->glyph
->advance
.x
>> 6;
685 // save the space glyph
688 NS_ASSERTION(0, "blah");
691 // properties of 'x', also use its width as average width
692 gid
= FT_Get_Char_Index(face
, 'x'); // select the glyph
694 // Load glyph into glyph slot. Here, use no_scale to get font units.
695 FT_Load_Glyph(face
, gid
, FT_LOAD_NO_SCALE
);
696 mMetrics
.xHeight
= face
->glyph
->metrics
.height
* yScale
;
697 mMetrics
.aveCharWidth
= face
->glyph
->metrics
.width
* xScale
;
699 // this font doesn't have an 'x'...
700 // fake these metrics using a fraction of the font size
701 mMetrics
.xHeight
= mMetrics
.emHeight
* 0.5;
702 mMetrics
.aveCharWidth
= mMetrics
.emHeight
* 0.5;
705 // compute an adjusted size if we need to
706 if (mAdjustedSize
== 0 && GetStyle()->sizeAdjust
!= 0) {
707 gfxFloat aspect
= mMetrics
.xHeight
/ GetStyle()->size
;
708 mAdjustedSize
= GetStyle()->GetAdjustedSize(aspect
);
709 mMetrics
.emHeight
= mAdjustedSize
;
712 // now load the OS/2 TrueType table to load access some more properties
713 TT_OS2
*os2
= (TT_OS2
*)FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
714 if (os2
&& os2
->version
!= 0xFFFF) { // should be there if not old Mac font
715 // if we are here we can improve the avgCharWidth
716 mMetrics
.aveCharWidth
= os2
->xAvgCharWidth
* xScale
;
718 mMetrics
.superscriptOffset
= os2
->ySuperscriptYOffset
* yScale
;
719 mMetrics
.superscriptOffset
= PR_MAX(1, mMetrics
.superscriptOffset
);
720 // some fonts have the incorrect sign (from gfxPangoFonts)
721 mMetrics
.subscriptOffset
= fabs(os2
->ySubscriptYOffset
* yScale
);
722 mMetrics
.subscriptOffset
= PR_MAX(1, fabs(mMetrics
.subscriptOffset
));
723 mMetrics
.strikeoutOffset
= os2
->yStrikeoutPosition
* yScale
;
724 mMetrics
.strikeoutSize
= os2
->yStrikeoutSize
* yScale
;
726 // use fractions of emHeight instead of xHeight for these to be more robust
727 mMetrics
.superscriptOffset
= mMetrics
.emHeight
* 0.5;
728 mMetrics
.subscriptOffset
= mMetrics
.emHeight
* 0.2;
729 mMetrics
.strikeoutOffset
= mMetrics
.emHeight
* 0.3;
730 mMetrics
.strikeoutSize
= face
->underline_thickness
* yScale
;
732 // seems that underlineOffset really has to be negative
733 mMetrics
.underlineOffset
= face
->underline_position
* yScale
;
734 mMetrics
.underlineSize
= face
->underline_thickness
* yScale
;
736 // descents are negative in FT but Thebes wants them positive
737 mMetrics
.emAscent
= face
->ascender
* yScale
;
738 mMetrics
.emDescent
= -face
->descender
* yScale
;
739 mMetrics
.maxHeight
= face
->height
* yScale
;
740 mMetrics
.maxAscent
= face
->bbox
.yMax
* yScale
;
741 mMetrics
.maxDescent
= -face
->bbox
.yMin
* yScale
;
742 mMetrics
.maxAdvance
= face
->max_advance_width
* xScale
;
743 // leading are not available directly (only for WinFNTs)
744 double lineHeight
= mMetrics
.maxAscent
+ mMetrics
.maxDescent
;
745 if (lineHeight
> mMetrics
.emHeight
) {
746 mMetrics
.internalLeading
= lineHeight
- mMetrics
.emHeight
;
748 mMetrics
.internalLeading
= 0;
750 mMetrics
.externalLeading
= 0; // normal value for OS/2 fonts, too
752 SanitizeMetrics(&mMetrics
, PR_FALSE
);
755 printf("gfxOS2Font[%#x]::GetMetrics():\n"
756 " emHeight=%f == %f=gfxFont::style.size == %f=adjSz\n"
757 " maxHeight=%f xHeight=%f\n"
758 " aveCharWidth=%f==xWidth spaceWidth=%f\n"
759 " supOff=%f SubOff=%f strOff=%f strSz=%f\n"
760 " undOff=%f undSz=%f intLead=%f extLead=%f\n"
761 " emAsc=%f emDesc=%f maxH=%f\n"
762 " maxAsc=%f maxDes=%f maxAdv=%f\n",
764 mMetrics.emHeight, GetStyle()->size, mAdjustedSize,
765 mMetrics.maxHeight, mMetrics.xHeight,
766 mMetrics.aveCharWidth, mMetrics.spaceWidth,
767 mMetrics.superscriptOffset, mMetrics.subscriptOffset,
768 mMetrics.strikeoutOffset, mMetrics.strikeoutSize,
769 mMetrics.underlineOffset, mMetrics.underlineSize,
770 mMetrics.internalLeading, mMetrics.externalLeading,
771 mMetrics.emAscent, mMetrics.emDescent, mMetrics.maxHeight,
772 mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance
776 // XXX mMetrics.height needs to be set.
777 cairo_ft_scaled_font_unlock_face(CairoScaledFont());
779 mHasMetrics
= PR_TRUE
;
785 gfxFT2Font::GetUniqueName()
791 gfxFT2Font::GetSpaceGlyph()
793 NS_ASSERTION (GetStyle ()->size
!= 0,
794 "forgot to short-circuit a text run with zero-sized font?");
798 FT_UInt gid
= 0; // glyph ID
799 FT_Face face
= cairo_ft_scaled_font_lock_face(CairoScaledFont());
800 gid
= FT_Get_Char_Index(face
, ' ');
801 FT_Load_Glyph(face
, gid
, FT_LOAD_DEFAULT
);
803 mHasSpaceGlyph
= PR_TRUE
;
804 cairo_ft_scaled_font_unlock_face(CairoScaledFont());
810 gfxFT2Font::CairoFontFace()
812 // XXX we need to handle fake bold here (or by having a sepaerate font entry)
813 if (mStyle
.weight
>= 600 && mFontEntry
->mWeight
< 600)
814 printf("** We want fake weight\n");
815 return GetFontEntry()->CairoFontFace();
818 cairo_scaled_font_t
*
819 gfxFT2Font::CairoScaledFont()
822 cairo_matrix_t sizeMatrix
;
823 cairo_matrix_t identityMatrix
;
825 // XXX deal with adjusted size
826 cairo_matrix_init_scale(&sizeMatrix
, mStyle
.size
, mStyle
.size
);
827 cairo_matrix_init_identity(&identityMatrix
);
829 // synthetic oblique by skewing via the font matrix
830 PRBool needsOblique
= (!mFontEntry
->mItalic
&& (mStyle
.style
& (FONT_STYLE_ITALIC
| FONT_STYLE_OBLIQUE
)));
833 const double kSkewFactor
= 0.25;
835 cairo_matrix_t style
;
836 cairo_matrix_init(&style
,
839 -1 * kSkewFactor
, //xy
843 cairo_matrix_multiply(&sizeMatrix
, &sizeMatrix
, &style
);
846 cairo_font_options_t
*fontOptions
= cairo_font_options_create();
847 mScaledFont
= cairo_scaled_font_create(CairoFontFace(), &sizeMatrix
,
848 &identityMatrix
, fontOptions
);
849 cairo_font_options_destroy(fontOptions
);
852 NS_ASSERTION(mAdjustedSize
== 0.0 ||
853 cairo_scaled_font_status(mScaledFont
) == CAIRO_STATUS_SUCCESS
,
854 "Failed to make scaled font");
860 gfxFT2Font::SetupCairoFont(gfxContext
*aContext
)
862 cairo_scaled_font_t
*scaledFont
= CairoScaledFont();
864 if (cairo_scaled_font_status(scaledFont
) != CAIRO_STATUS_SUCCESS
) {
865 // Don't cairo_set_scaled_font as that would propagate the error to
866 // the cairo_t, precluding any further drawing.
869 cairo_set_scaled_font(aContext
->GetCairo(), scaledFont
);