1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #if defined(MOZ_WIDGET_GTK)
7 # include "gfxPlatformGtk.h"
8 # define gfxToolkitPlatform gfxPlatformGtk
10 # include "gfxWindowsPlatform.h"
11 # define gfxToolkitPlatform gfxWindowsPlatform
12 #elif defined(ANDROID)
13 # include "gfxAndroidPlatform.h"
14 # define gfxToolkitPlatform gfxAndroidPlatform
18 #include "gfxFT2Fonts.h"
19 #include "gfxFT2FontBase.h"
20 #include "gfxFT2Utils.h"
21 #include "gfxFT2FontList.h"
22 #include "gfxTextRun.h"
24 #include "nsGkAtoms.h"
27 #include "nsXULAppAPI.h"
29 #include "mozilla/Logging.h"
32 #include "mozilla/MemoryReporting.h"
33 #include "mozilla/Preferences.h"
34 #include "mozilla/gfx/2D.h"
36 using namespace mozilla
;
37 using namespace mozilla::gfx
;
43 bool gfxFT2Font::ShapeText(DrawTarget
* aDrawTarget
, const char16_t
* aText
,
44 uint32_t aOffset
, uint32_t aLength
, Script aScript
,
45 nsAtom
* aLanguage
, bool aVertical
,
46 RoundingFlags aRounding
,
47 gfxShapedText
* aShapedText
) {
48 if (!gfxFont::ShapeText(aDrawTarget
, aText
, aOffset
, aLength
, aScript
,
49 aLanguage
, aVertical
, aRounding
, aShapedText
)) {
50 // harfbuzz must have failed(?!), just render raw glyphs
51 AddRange(aText
, aOffset
, aLength
, aShapedText
);
52 PostShapingFixup(aDrawTarget
, aText
, aOffset
, aLength
, aVertical
,
59 void gfxFT2Font::AddRange(const char16_t
* aText
, uint32_t aOffset
,
60 uint32_t aLength
, gfxShapedText
* aShapedText
) {
61 typedef gfxShapedText::CompressedGlyph CompressedGlyph
;
63 const uint32_t appUnitsPerDevUnit
= aShapedText
->GetAppUnitsPerDevUnit();
64 // we'll pass this in/figure it out dynamically, but at this point there can
66 gfxFT2LockedFace
faceLock(this);
67 FT_Face face
= faceLock
.get();
69 CompressedGlyph
* charGlyphs
= aShapedText
->GetCharacterGlyphs();
71 const gfxFT2Font::CachedGlyphData
*cgd
= nullptr, *cgdNext
= nullptr;
73 FT_UInt spaceGlyph
= GetSpaceGlyph();
75 for (uint32_t i
= 0; i
< aLength
; i
++, aOffset
++) {
76 char16_t ch
= aText
[i
];
79 // treat this null byte as a missing glyph, don't create a glyph for it
80 aShapedText
->SetMissingGlyph(aOffset
, 0, this);
84 NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch
), "Invalid char detected");
90 cgd
= GetGlyphDataForChar(face
, ch
);
93 FT_UInt gid
= cgd
->glyphIndex
;
97 advance
= -1; // trigger the missing glyphs case below
99 // find next character and its glyph -- in case they exist
100 // and exist in the current font face -- to compute kerning
103 FT_Pos lsbDeltaNext
= 0;
105 if (FT_HAS_KERNING(face
) && i
+ 1 < aLength
) {
106 chNext
= aText
[i
+ 1];
108 cgdNext
= GetGlyphDataForChar(face
, chNext
);
109 gidNext
= cgdNext
->glyphIndex
;
110 if (gidNext
&& gidNext
!= spaceGlyph
)
111 lsbDeltaNext
= cgdNext
->lsbDelta
;
115 advance
= cgd
->xAdvance
;
117 // now add kerning to the current glyph's advance
118 if (chNext
&& gidNext
) {
121 FT_Get_Kerning(face
, gid
, gidNext
, FT_KERNING_DEFAULT
, &kerning
);
122 advance
+= kerning
.x
;
123 if (cgd
->rsbDelta
- lsbDeltaNext
>= 32) {
125 } else if (cgd
->rsbDelta
- lsbDeltaNext
< -32) {
130 // convert 26.6 fixed point to app units
131 // round rather than truncate to nearest pixel
132 // because these advances are often scaled
133 advance
= ((advance
* appUnitsPerDevUnit
+ 32) >> 6);
136 if (advance
>= 0 && CompressedGlyph::IsSimpleAdvance(advance
) &&
137 CompressedGlyph::IsSimpleGlyphID(gid
)) {
138 charGlyphs
[aOffset
].SetSimpleGlyph(advance
, gid
);
139 } else if (gid
== 0) {
140 // gid = 0 only happens when the glyph is missing from the font
141 aShapedText
->SetMissingGlyph(aOffset
, ch
, this);
143 gfxTextRun::DetailedGlyph details
;
144 details
.mGlyphID
= gid
;
145 NS_ASSERTION(details
.mGlyphID
== gid
,
146 "Seriously weird glyph ID detected!");
147 details
.mAdvance
= advance
;
148 aShapedText
->SetDetailedGlyphs(aOffset
, 1, &details
);
153 gfxFT2Font::gfxFT2Font(const RefPtr
<UnscaledFontFreeType
>& aUnscaledFont
,
154 RefPtr
<mozilla::gfx::SharedFTFace
>&& aFTFace
,
155 FT2FontEntry
* aFontEntry
, const gfxFontStyle
* aFontStyle
,
157 : gfxFT2FontBase(aUnscaledFont
, std::move(aFTFace
), aFontEntry
, aFontStyle
,
158 aLoadFlags
, aFontStyle
->NeedsSyntheticBold(aFontEntry
)),
159 mCharGlyphCache(32) {
160 NS_ASSERTION(mFontEntry
,
161 "Unable to find font entry for font. Something is whack.");
165 gfxFT2Font::~gfxFT2Font() {}
167 already_AddRefed
<ScaledFont
> gfxFT2Font::GetScaledFont(
168 const TextRunDrawParams
& aRunParams
) {
169 if (ScaledFont
* scaledFont
= mAzureScaledFont
) {
170 return do_AddRef(scaledFont
);
173 RefPtr
<ScaledFont
> newScaledFont
= Factory::CreateScaledFontForFreeTypeFont(
174 GetUnscaledFont(), GetAdjustedSize(), mFTFace
,
175 GetStyle()->NeedsSyntheticBold(GetFontEntry()));
176 if (!newScaledFont
) {
180 InitializeScaledFont(newScaledFont
);
182 if (mAzureScaledFont
.compareExchange(nullptr, newScaledFont
.get())) {
183 Unused
<< newScaledFont
.forget();
185 ScaledFont
* scaledFont
= mAzureScaledFont
;
186 return do_AddRef(scaledFont
);
189 bool gfxFT2Font::ShouldHintMetrics() const {
190 return !gfxPlatform::GetPlatform()->RequiresLinearZoom();
193 void gfxFT2Font::FillGlyphDataForChar(FT_Face face
, uint32_t ch
,
194 CachedGlyphData
* gd
) {
195 if (!face
->charmap
|| (face
->charmap
->encoding
!= FT_ENCODING_UNICODE
&&
196 face
->charmap
->encoding
!= FT_ENCODING_MS_SYMBOL
)) {
197 if (FT_Err_Ok
!= FT_Select_Charmap(face
, FT_ENCODING_UNICODE
) &&
198 FT_Err_Ok
!= FT_Select_Charmap(face
, FT_ENCODING_MS_SYMBOL
)) {
199 NS_WARNING("failed to select Unicode or symbol charmap!");
202 FT_UInt gid
= FT_Get_Char_Index(face
, ch
);
205 // this font doesn't support this char!
206 NS_ASSERTION(gid
!= 0,
207 "We don't have a glyph, but font indicated that it supported "
208 "this char in tables?");
213 FT_Error err
= Factory::LoadFTGlyph(face
, gid
, mFTLoadFlags
);
216 // hmm, this is weird, we failed to load a glyph that we had?
217 NS_WARNING("Failed to load glyph that we got from Get_Char_index");
223 gd
->glyphIndex
= gid
;
224 gd
->lsbDelta
= face
->glyph
->lsb_delta
;
225 gd
->rsbDelta
= face
->glyph
->rsb_delta
;
226 gd
->xAdvance
= face
->glyph
->advance
.x
;
228 gd
->xAdvance
+= GetEmboldenStrength(face
).x
;
232 void gfxFT2Font::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf
,
233 FontCacheSizes
* aSizes
) const {
234 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);
235 aSizes
->mFontInstances
+=
236 mCharGlyphCache
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
239 void gfxFT2Font::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf
,
240 FontCacheSizes
* aSizes
) const {
241 aSizes
->mFontInstances
+= aMallocSizeOf(this);
242 AddSizeOfExcludingThis(aMallocSizeOf
, aSizes
);