no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / gfx / thebes / gfxFT2Fonts.cpp
blob9cc3a4bfd5f1394d4ad88ebde6f6fb8332f270e5
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
9 #elif defined(XP_WIN)
10 # include "gfxWindowsPlatform.h"
11 # define gfxToolkitPlatform gfxWindowsPlatform
12 #elif defined(ANDROID)
13 # include "gfxAndroidPlatform.h"
14 # define gfxToolkitPlatform gfxAndroidPlatform
15 #endif
17 #include "gfxTypes.h"
18 #include "gfxFT2Fonts.h"
19 #include "gfxFT2FontBase.h"
20 #include "gfxFT2Utils.h"
21 #include "gfxFT2FontList.h"
22 #include "gfxTextRun.h"
23 #include <locale.h>
24 #include "nsGkAtoms.h"
25 #include "nsTArray.h"
26 #include "nsCRT.h"
27 #include "nsXULAppAPI.h"
29 #include "mozilla/Logging.h"
30 #include "prinit.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;
39 /**
40 * gfxFT2Font
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,
53 aShapedText);
56 return true;
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
65 // be only one face.
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];
78 if (ch == 0) {
79 // treat this null byte as a missing glyph, don't create a glyph for it
80 aShapedText->SetMissingGlyph(aOffset, 0, this);
81 continue;
84 NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected");
86 if (cgdNext) {
87 cgd = cgdNext;
88 cgdNext = nullptr;
89 } else {
90 cgd = GetGlyphDataForChar(face, ch);
93 FT_UInt gid = cgd->glyphIndex;
94 int32_t advance = 0;
96 if (gid == 0) {
97 advance = -1; // trigger the missing glyphs case below
98 } else {
99 // find next character and its glyph -- in case they exist
100 // and exist in the current font face -- to compute kerning
101 char16_t chNext = 0;
102 FT_UInt gidNext = 0;
103 FT_Pos lsbDeltaNext = 0;
105 if (FT_HAS_KERNING(face) && i + 1 < aLength) {
106 chNext = aText[i + 1];
107 if (chNext != 0) {
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) {
119 FT_Vector kerning;
120 kerning.x = 0;
121 FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning);
122 advance += kerning.x;
123 if (cgd->rsbDelta - lsbDeltaNext >= 32) {
124 advance -= 64;
125 } else if (cgd->rsbDelta - lsbDeltaNext < -32) {
126 advance += 64;
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);
142 } else {
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,
156 int aLoadFlags)
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.");
162 InitMetrics();
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) {
177 return nullptr;
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);
204 if (gid == 0) {
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?");
209 gd->glyphIndex = 0;
210 return;
213 FT_Error err = Factory::LoadFTGlyph(face, gid, mFTLoadFlags);
215 if (err) {
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");
219 gd->glyphIndex = 0;
220 return;
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;
227 if (gd->xAdvance) {
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);