Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxFT2Fonts.cpp
blobdeb055d8af4e24e9dd7b8bf57610f8236bd5895d
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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
9 #elif defined(MOZ_WIDGET_QT)
10 #include <qfontinfo.h>
11 #include "gfxQtPlatform.h"
12 #define gfxToolkitPlatform gfxQtPlatform
13 #elif defined(XP_WIN)
14 #include "gfxWindowsPlatform.h"
15 #define gfxToolkitPlatform gfxWindowsPlatform
16 #elif defined(ANDROID)
17 #include "gfxAndroidPlatform.h"
18 #define gfxToolkitPlatform gfxAndroidPlatform
19 #endif
21 #include "gfxTypes.h"
22 #include "gfxFT2Fonts.h"
23 #include "gfxFT2FontBase.h"
24 #include "gfxFT2Utils.h"
25 #include "gfxFT2FontList.h"
26 #include <locale.h>
27 #include "nsGkAtoms.h"
28 #include "nsTArray.h"
29 #include "nsUnicodeRange.h"
30 #include "nsCRT.h"
31 #include "nsXULAppAPI.h"
33 #include "prlog.h"
34 #include "prinit.h"
36 #include "mozilla/MemoryReporting.h"
37 #include "mozilla/Preferences.h"
38 #include "mozilla/gfx/2D.h"
40 /**
41 * gfxFT2Font
44 bool
45 gfxFT2Font::ShapeText(gfxContext *aContext,
46 const char16_t *aText,
47 uint32_t aOffset,
48 uint32_t aLength,
49 int32_t aScript,
50 gfxShapedText *aShapedText)
52 if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
53 aShapedText)) {
54 // harfbuzz must have failed(?!), just render raw glyphs
55 AddRange(aText, aOffset, aLength, aShapedText);
56 PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
59 return true;
62 void
63 gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
64 uint32_t aLength, gfxShapedText *aShapedText)
66 const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
67 // we'll pass this in/figure it out dynamically, but at this point there can be only one face.
68 gfxFT2LockedFace faceLock(this);
69 FT_Face face = faceLock.get();
71 gfxShapedText::CompressedGlyph *charGlyphs =
72 aShapedText->GetCharacterGlyphs();
74 const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
76 FT_UInt spaceGlyph = GetSpaceGlyph();
78 for (uint32_t i = 0; i < aLength; i++, aOffset++) {
79 char16_t ch = aText[i];
81 if (ch == 0) {
82 // treat this null byte as a missing glyph, don't create a glyph for it
83 aShapedText->SetMissingGlyph(aOffset, 0, this);
84 continue;
87 NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected");
89 if (cgdNext) {
90 cgd = cgdNext;
91 cgdNext = nullptr;
92 } else {
93 cgd = GetGlyphDataForChar(ch);
96 FT_UInt gid = cgd->glyphIndex;
97 int32_t advance = 0;
99 if (gid == 0) {
100 advance = -1; // trigger the missing glyphs case below
101 } else {
102 // find next character and its glyph -- in case they exist
103 // and exist in the current font face -- to compute kerning
104 char16_t chNext = 0;
105 FT_UInt gidNext = 0;
106 FT_Pos lsbDeltaNext = 0;
108 if (FT_HAS_KERNING(face) && i + 1 < aLength) {
109 chNext = aText[i + 1];
110 if (chNext != 0) {
111 cgdNext = GetGlyphDataForChar(chNext);
112 gidNext = cgdNext->glyphIndex;
113 if (gidNext && gidNext != spaceGlyph)
114 lsbDeltaNext = cgdNext->lsbDelta;
118 advance = cgd->xAdvance;
120 // now add kerning to the current glyph's advance
121 if (chNext && gidNext) {
122 FT_Vector kerning; kerning.x = 0;
123 FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning);
124 advance += kerning.x;
125 if (cgd->rsbDelta - lsbDeltaNext >= 32) {
126 advance -= 64;
127 } else if (cgd->rsbDelta - lsbDeltaNext < -32) {
128 advance += 64;
132 // convert 26.6 fixed point to app units
133 // round rather than truncate to nearest pixel
134 // because these advances are often scaled
135 advance = ((advance * appUnitsPerDevUnit + 32) >> 6);
138 if (advance >= 0 &&
139 gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
140 gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) {
141 charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
142 } else if (gid == 0) {
143 // gid = 0 only happens when the glyph is missing from the font
144 aShapedText->SetMissingGlyph(aOffset, ch, this);
145 } else {
146 gfxTextRun::DetailedGlyph details;
147 details.mGlyphID = gid;
148 NS_ASSERTION(details.mGlyphID == gid,
149 "Seriously weird glyph ID detected!");
150 details.mAdvance = advance;
151 details.mXOffset = 0;
152 details.mYOffset = 0;
153 gfxShapedText::CompressedGlyph g;
154 g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1);
155 aShapedText->SetGlyphs(aOffset, g, &details);
160 gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont,
161 FT2FontEntry *aFontEntry,
162 const gfxFontStyle *aFontStyle,
163 bool aNeedsBold)
164 : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle)
165 , mCharGlyphCache(32)
167 NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack.");
168 mApplySyntheticBold = aNeedsBold;
171 gfxFT2Font::~gfxFT2Font()
176 * Look up the font in the gfxFont cache. If we don't find it, create one.
177 * In either case, add a ref, append it to the aFonts array, and return it ---
178 * except for OOM in which case we do nothing and return null.
180 already_AddRefed<gfxFT2Font>
181 gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle,
182 bool aNeedsBold)
184 #ifdef ANDROID
185 FT2FontEntry *fe = static_cast<FT2FontEntry*>
186 (gfxPlatformFontList::PlatformFontList()->
187 FindFontForFamily(aName, aStyle, aNeedsBold));
188 #else
189 FT2FontEntry *fe = static_cast<FT2FontEntry*>
190 (gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle));
191 #endif
192 if (!fe) {
193 NS_WARNING("Failed to find font entry for font!");
194 return nullptr;
197 nsRefPtr<gfxFT2Font> font = GetOrMakeFont(fe, aStyle, aNeedsBold);
198 return font.forget();
201 already_AddRefed<gfxFT2Font>
202 gfxFT2Font::GetOrMakeFont(FT2FontEntry *aFontEntry, const gfxFontStyle *aStyle,
203 bool aNeedsBold)
205 nsRefPtr<gfxFont> font = gfxFontCache::GetCache()->Lookup(aFontEntry, aStyle);
206 if (!font) {
207 cairo_scaled_font_t *scaledFont = aFontEntry->CreateScaledFont(aStyle);
208 if (!scaledFont) {
209 return nullptr;
211 font = new gfxFT2Font(scaledFont, aFontEntry, aStyle, aNeedsBold);
212 cairo_scaled_font_destroy(scaledFont);
213 if (!font) {
214 return nullptr;
216 gfxFontCache::GetCache()->AddNew(font);
218 return font.forget().downcast<gfxFT2Font>();
221 void
222 gfxFT2Font::FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd)
224 gfxFT2LockedFace faceLock(this);
225 FT_Face face = faceLock.get();
227 if (!face->charmap || face->charmap->encoding != FT_ENCODING_UNICODE) {
228 FT_Select_Charmap(face, FT_ENCODING_UNICODE);
230 FT_UInt gid = FT_Get_Char_Index(face, ch);
232 if (gid == 0) {
233 // this font doesn't support this char!
234 NS_ASSERTION(gid != 0, "We don't have a glyph, but font indicated that it supported this char in tables?");
235 gd->glyphIndex = 0;
236 return;
239 FT_Int32 flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
240 FT_LOAD_DEFAULT :
241 (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
242 FT_Error err = FT_Load_Glyph(face, gid, flags);
244 if (err) {
245 // hmm, this is weird, we failed to load a glyph that we had?
246 NS_WARNING("Failed to load glyph that we got from Get_Char_index");
248 gd->glyphIndex = 0;
249 return;
252 gd->glyphIndex = gid;
253 gd->lsbDelta = face->glyph->lsb_delta;
254 gd->rsbDelta = face->glyph->rsb_delta;
255 gd->xAdvance = face->glyph->advance.x;
258 void
259 gfxFT2Font::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
260 FontCacheSizes* aSizes) const
262 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
263 aSizes->mFontInstances +=
264 mCharGlyphCache.SizeOfExcludingThis(nullptr, aMallocSizeOf);
267 void
268 gfxFT2Font::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
269 FontCacheSizes* aSizes) const
271 aSizes->mFontInstances += aMallocSizeOf(this);
272 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
275 #ifdef USE_SKIA
276 mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
277 gfxFT2Font::GetGlyphRenderingOptions()
279 mozilla::gfx::FontHinting hinting;
281 if (gfxPlatform::GetPlatform()->FontHintingEnabled()) {
282 hinting = mozilla::gfx::FontHinting::NORMAL;
283 } else {
284 hinting = mozilla::gfx::FontHinting::NONE;
287 // We don't want to force the use of the autohinter over the font's built in hints
288 return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false);
290 #endif