diff options
Diffstat (limited to 'gfx/thebes/gfxFT2Fonts.cpp')
-rw-r--r-- | gfx/thebes/gfxFT2Fonts.cpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/gfx/thebes/gfxFT2Fonts.cpp b/gfx/thebes/gfxFT2Fonts.cpp new file mode 100644 index 0000000000..9cc3a4bfd5 --- /dev/null +++ b/gfx/thebes/gfxFT2Fonts.cpp @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZ_WIDGET_GTK) +# include "gfxPlatformGtk.h" +# define gfxToolkitPlatform gfxPlatformGtk +#elif defined(XP_WIN) +# include "gfxWindowsPlatform.h" +# define gfxToolkitPlatform gfxWindowsPlatform +#elif defined(ANDROID) +# include "gfxAndroidPlatform.h" +# define gfxToolkitPlatform gfxAndroidPlatform +#endif + +#include "gfxTypes.h" +#include "gfxFT2Fonts.h" +#include "gfxFT2FontBase.h" +#include "gfxFT2Utils.h" +#include "gfxFT2FontList.h" +#include "gfxTextRun.h" +#include <locale.h> +#include "nsGkAtoms.h" +#include "nsTArray.h" +#include "nsCRT.h" +#include "nsXULAppAPI.h" + +#include "mozilla/Logging.h" +#include "prinit.h" + +#include "mozilla/MemoryReporting.h" +#include "mozilla/Preferences.h" +#include "mozilla/gfx/2D.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +/** + * gfxFT2Font + */ + +bool gfxFT2Font::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText, + uint32_t aOffset, uint32_t aLength, Script aScript, + nsAtom* aLanguage, bool aVertical, + RoundingFlags aRounding, + gfxShapedText* aShapedText) { + if (!gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript, + aLanguage, aVertical, aRounding, aShapedText)) { + // harfbuzz must have failed(?!), just render raw glyphs + AddRange(aText, aOffset, aLength, aShapedText); + PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical, + aShapedText); + } + + return true; +} + +void gfxFT2Font::AddRange(const char16_t* aText, uint32_t aOffset, + uint32_t aLength, gfxShapedText* aShapedText) { + typedef gfxShapedText::CompressedGlyph CompressedGlyph; + + const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit(); + // we'll pass this in/figure it out dynamically, but at this point there can + // be only one face. + gfxFT2LockedFace faceLock(this); + FT_Face face = faceLock.get(); + + CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs(); + + const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr; + + FT_UInt spaceGlyph = GetSpaceGlyph(); + + for (uint32_t i = 0; i < aLength; i++, aOffset++) { + char16_t ch = aText[i]; + + if (ch == 0) { + // treat this null byte as a missing glyph, don't create a glyph for it + aShapedText->SetMissingGlyph(aOffset, 0, this); + continue; + } + + NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected"); + + if (cgdNext) { + cgd = cgdNext; + cgdNext = nullptr; + } else { + cgd = GetGlyphDataForChar(face, ch); + } + + FT_UInt gid = cgd->glyphIndex; + int32_t advance = 0; + + if (gid == 0) { + advance = -1; // trigger the missing glyphs case below + } else { + // find next character and its glyph -- in case they exist + // and exist in the current font face -- to compute kerning + char16_t chNext = 0; + FT_UInt gidNext = 0; + FT_Pos lsbDeltaNext = 0; + + if (FT_HAS_KERNING(face) && i + 1 < aLength) { + chNext = aText[i + 1]; + if (chNext != 0) { + cgdNext = GetGlyphDataForChar(face, chNext); + gidNext = cgdNext->glyphIndex; + if (gidNext && gidNext != spaceGlyph) + lsbDeltaNext = cgdNext->lsbDelta; + } + } + + advance = cgd->xAdvance; + + // now add kerning to the current glyph's advance + if (chNext && gidNext) { + FT_Vector kerning; + kerning.x = 0; + FT_Get_Kerning(face, gid, gidNext, FT_KERNING_DEFAULT, &kerning); + advance += kerning.x; + if (cgd->rsbDelta - lsbDeltaNext >= 32) { + advance -= 64; + } else if (cgd->rsbDelta - lsbDeltaNext < -32) { + advance += 64; + } + } + + // convert 26.6 fixed point to app units + // round rather than truncate to nearest pixel + // because these advances are often scaled + advance = ((advance * appUnitsPerDevUnit + 32) >> 6); + } + + if (advance >= 0 && CompressedGlyph::IsSimpleAdvance(advance) && + CompressedGlyph::IsSimpleGlyphID(gid)) { + charGlyphs[aOffset].SetSimpleGlyph(advance, gid); + } else if (gid == 0) { + // gid = 0 only happens when the glyph is missing from the font + aShapedText->SetMissingGlyph(aOffset, ch, this); + } else { + gfxTextRun::DetailedGlyph details; + details.mGlyphID = gid; + NS_ASSERTION(details.mGlyphID == gid, + "Seriously weird glyph ID detected!"); + details.mAdvance = advance; + aShapedText->SetDetailedGlyphs(aOffset, 1, &details); + } + } +} + +gfxFT2Font::gfxFT2Font(const RefPtr<UnscaledFontFreeType>& aUnscaledFont, + RefPtr<mozilla::gfx::SharedFTFace>&& aFTFace, + FT2FontEntry* aFontEntry, const gfxFontStyle* aFontStyle, + int aLoadFlags) + : gfxFT2FontBase(aUnscaledFont, std::move(aFTFace), aFontEntry, aFontStyle, + aLoadFlags, aFontStyle->NeedsSyntheticBold(aFontEntry)), + mCharGlyphCache(32) { + NS_ASSERTION(mFontEntry, + "Unable to find font entry for font. Something is whack."); + InitMetrics(); +} + +gfxFT2Font::~gfxFT2Font() {} + +already_AddRefed<ScaledFont> gfxFT2Font::GetScaledFont( + const TextRunDrawParams& aRunParams) { + if (ScaledFont* scaledFont = mAzureScaledFont) { + return do_AddRef(scaledFont); + } + + RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForFreeTypeFont( + GetUnscaledFont(), GetAdjustedSize(), mFTFace, + GetStyle()->NeedsSyntheticBold(GetFontEntry())); + if (!newScaledFont) { + return nullptr; + } + + InitializeScaledFont(newScaledFont); + + if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) { + Unused << newScaledFont.forget(); + } + ScaledFont* scaledFont = mAzureScaledFont; + return do_AddRef(scaledFont); +} + +bool gfxFT2Font::ShouldHintMetrics() const { + return !gfxPlatform::GetPlatform()->RequiresLinearZoom(); +} + +void gfxFT2Font::FillGlyphDataForChar(FT_Face face, uint32_t ch, + CachedGlyphData* gd) { + if (!face->charmap || (face->charmap->encoding != FT_ENCODING_UNICODE && + face->charmap->encoding != FT_ENCODING_MS_SYMBOL)) { + if (FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_UNICODE) && + FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_MS_SYMBOL)) { + NS_WARNING("failed to select Unicode or symbol charmap!"); + } + } + FT_UInt gid = FT_Get_Char_Index(face, ch); + + if (gid == 0) { + // this font doesn't support this char! + NS_ASSERTION(gid != 0, + "We don't have a glyph, but font indicated that it supported " + "this char in tables?"); + gd->glyphIndex = 0; + return; + } + + FT_Error err = Factory::LoadFTGlyph(face, gid, mFTLoadFlags); + + if (err) { + // hmm, this is weird, we failed to load a glyph that we had? + NS_WARNING("Failed to load glyph that we got from Get_Char_index"); + + gd->glyphIndex = 0; + return; + } + + gd->glyphIndex = gid; + gd->lsbDelta = face->glyph->lsb_delta; + gd->rsbDelta = face->glyph->rsb_delta; + gd->xAdvance = face->glyph->advance.x; + if (gd->xAdvance) { + gd->xAdvance += GetEmboldenStrength(face).x; + } +} + +void gfxFT2Font::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, + FontCacheSizes* aSizes) const { + gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); + aSizes->mFontInstances += + mCharGlyphCache.ShallowSizeOfExcludingThis(aMallocSizeOf); +} + +void gfxFT2Font::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, + FontCacheSizes* aSizes) const { + aSizes->mFontInstances += aMallocSizeOf(this); + AddSizeOfExcludingThis(aMallocSizeOf, aSizes); +} |