2008-08-06 20:48:55 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2012-05-21 11:12:37 +00:00
|
|
|
* 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/. */
|
2008-08-06 20:48:55 +00:00
|
|
|
|
2012-06-28 00:15:32 +00:00
|
|
|
#if defined(MOZ_WIDGET_GTK)
|
2008-08-06 20:48:55 +00:00
|
|
|
#include "gfxPlatformGtk.h"
|
2008-08-28 11:05:53 +00:00
|
|
|
#define gfxToolkitPlatform gfxPlatformGtk
|
2009-01-23 06:24:29 +00:00
|
|
|
#elif defined(XP_WIN)
|
|
|
|
#include "gfxWindowsPlatform.h"
|
|
|
|
#define gfxToolkitPlatform gfxWindowsPlatform
|
2010-05-11 17:27:36 +00:00
|
|
|
#elif defined(ANDROID)
|
|
|
|
#include "gfxAndroidPlatform.h"
|
|
|
|
#define gfxToolkitPlatform gfxAndroidPlatform
|
2008-08-28 11:05:53 +00:00
|
|
|
#endif
|
2010-05-11 17:27:36 +00:00
|
|
|
|
2008-08-06 20:48:55 +00:00
|
|
|
#include "gfxTypes.h"
|
|
|
|
#include "gfxFT2Fonts.h"
|
2009-10-30 23:13:41 +00:00
|
|
|
#include "gfxFT2FontBase.h"
|
|
|
|
#include "gfxFT2Utils.h"
|
2011-09-23 11:15:36 +00:00
|
|
|
#include "gfxFT2FontList.h"
|
2014-09-16 09:58:12 +00:00
|
|
|
#include "gfxTextRun.h"
|
2008-08-06 20:48:55 +00:00
|
|
|
#include <locale.h>
|
2012-03-29 21:08:43 +00:00
|
|
|
#include "nsGkAtoms.h"
|
2009-01-18 20:14:14 +00:00
|
|
|
#include "nsTArray.h"
|
2009-09-09 15:35:08 +00:00
|
|
|
#include "nsUnicodeRange.h"
|
|
|
|
#include "nsCRT.h"
|
2012-02-08 22:52:57 +00:00
|
|
|
#include "nsXULAppAPI.h"
|
2009-09-09 15:35:08 +00:00
|
|
|
|
2015-05-19 18:15:34 +00:00
|
|
|
#include "mozilla/Logging.h"
|
2009-09-09 15:35:08 +00:00
|
|
|
#include "prinit.h"
|
2011-06-12 02:30:16 +00:00
|
|
|
|
2013-06-23 12:03:39 +00:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2011-06-12 02:30:16 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2013-06-05 17:48:59 +00:00
|
|
|
#include "mozilla/gfx/2D.h"
|
2011-06-12 02:30:16 +00:00
|
|
|
|
2017-08-07 20:20:44 +00:00
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
|
2010-12-09 11:57:23 +00:00
|
|
|
/**
|
|
|
|
* gfxFT2Font
|
|
|
|
*/
|
2009-09-10 20:52:40 +00:00
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2015-12-15 21:56:41 +00:00
|
|
|
gfxFT2Font::ShapeText(DrawTarget *aDrawTarget,
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t *aText,
|
2014-05-31 07:12:40 +00:00
|
|
|
uint32_t aOffset,
|
|
|
|
uint32_t aLength,
|
2016-04-21 17:58:59 +00:00
|
|
|
Script aScript,
|
2014-10-01 19:25:48 +00:00
|
|
|
bool aVertical,
|
2017-04-03 16:49:17 +00:00
|
|
|
RoundingFlags aRounding,
|
2014-05-31 07:12:40 +00:00
|
|
|
gfxShapedText *aShapedText)
|
2010-12-09 11:57:23 +00:00
|
|
|
{
|
2015-12-15 21:56:41 +00:00
|
|
|
if (!gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
|
2017-04-03 16:49:17 +00:00
|
|
|
aVertical, aRounding, aShapedText)) {
|
2014-05-31 07:12:40 +00:00
|
|
|
// harfbuzz must have failed(?!), just render raw glyphs
|
2013-01-04 18:35:37 +00:00
|
|
|
AddRange(aText, aOffset, aLength, aShapedText);
|
2015-12-15 21:56:41 +00:00
|
|
|
PostShapingFixup(aDrawTarget, aText, aOffset, aLength,
|
2015-12-15 21:56:40 +00:00
|
|
|
aVertical, aShapedText);
|
2010-12-09 11:58:16 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2008-08-06 20:48:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-01-04 15:02:17 +00:00
|
|
|
gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
|
2013-01-04 18:35:37 +00:00
|
|
|
uint32_t aLength, gfxShapedText *aShapedText)
|
2008-08-06 20:48:55 +00:00
|
|
|
{
|
2013-01-04 18:35:37 +00:00
|
|
|
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
2008-08-06 20:48:55 +00:00
|
|
|
// we'll pass this in/figure it out dynamically, but at this point there can be only one face.
|
2010-12-09 11:57:23 +00:00
|
|
|
gfxFT2LockedFace faceLock(this);
|
2009-10-30 23:13:41 +00:00
|
|
|
FT_Face face = faceLock.get();
|
2008-08-06 20:48:55 +00:00
|
|
|
|
2013-01-04 18:35:37 +00:00
|
|
|
gfxShapedText::CompressedGlyph *charGlyphs =
|
|
|
|
aShapedText->GetCharacterGlyphs();
|
2008-08-06 20:48:55 +00:00
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
|
2009-09-10 20:52:40 +00:00
|
|
|
|
2010-12-09 11:57:23 +00:00
|
|
|
FT_UInt spaceGlyph = GetSpaceGlyph();
|
2009-09-10 20:52:40 +00:00
|
|
|
|
2013-01-04 18:35:37 +00:00
|
|
|
for (uint32_t i = 0; i < aLength; i++, aOffset++) {
|
2014-01-04 15:02:17 +00:00
|
|
|
char16_t ch = aText[i];
|
2008-08-06 20:48:55 +00:00
|
|
|
|
|
|
|
if (ch == 0) {
|
|
|
|
// treat this null byte as a missing glyph, don't create a glyph for it
|
2013-01-04 18:35:37 +00:00
|
|
|
aShapedText->SetMissingGlyph(aOffset, 0, this);
|
2008-08-06 20:48:55 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-12-09 11:57:23 +00:00
|
|
|
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(ch), "Invalid char detected");
|
2009-09-10 20:52:40 +00:00
|
|
|
|
|
|
|
if (cgdNext) {
|
|
|
|
cgd = cgdNext;
|
2012-07-30 14:20:58 +00:00
|
|
|
cgdNext = nullptr;
|
2009-09-10 20:52:40 +00:00
|
|
|
} else {
|
2017-07-27 03:24:48 +00:00
|
|
|
cgd = GetGlyphDataForChar(face, ch);
|
2009-09-10 20:52:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FT_UInt gid = cgd->glyphIndex;
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t advance = 0;
|
2008-08-06 20:48:55 +00:00
|
|
|
|
2009-09-10 20:52:40 +00:00
|
|
|
if (gid == 0) {
|
2008-08-06 20:48:55 +00:00
|
|
|
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
|
2014-01-04 15:02:17 +00:00
|
|
|
char16_t chNext = 0;
|
2008-08-06 20:48:55 +00:00
|
|
|
FT_UInt gidNext = 0;
|
|
|
|
FT_Pos lsbDeltaNext = 0;
|
|
|
|
|
2013-01-04 18:35:37 +00:00
|
|
|
if (FT_HAS_KERNING(face) && i + 1 < aLength) {
|
|
|
|
chNext = aText[i + 1];
|
2008-08-06 20:48:55 +00:00
|
|
|
if (chNext != 0) {
|
2017-07-27 03:24:48 +00:00
|
|
|
cgdNext = GetGlyphDataForChar(face, chNext);
|
2009-09-10 20:52:40 +00:00
|
|
|
gidNext = cgdNext->glyphIndex;
|
|
|
|
if (gidNext && gidNext != spaceGlyph)
|
|
|
|
lsbDeltaNext = cgdNext->lsbDelta;
|
2008-08-06 20:48:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-10 20:52:40 +00:00
|
|
|
advance = cgd->xAdvance;
|
2008-08-06 20:48:55 +00:00
|
|
|
|
|
|
|
// 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;
|
2009-09-10 20:52:40 +00:00
|
|
|
if (cgd->rsbDelta - lsbDeltaNext >= 32) {
|
2008-08-06 20:48:55 +00:00
|
|
|
advance -= 64;
|
2009-09-10 20:52:40 +00:00
|
|
|
} else if (cgd->rsbDelta - lsbDeltaNext < -32) {
|
2008-08-06 20:48:55 +00:00
|
|
|
advance += 64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-09 20:18:17 +00:00
|
|
|
// 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);
|
2008-08-06 20:48:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (advance >= 0 &&
|
2013-01-04 18:35:37 +00:00
|
|
|
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
|
|
|
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) {
|
|
|
|
charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
|
2008-08-06 20:48:55 +00:00
|
|
|
} else if (gid == 0) {
|
|
|
|
// gid = 0 only happens when the glyph is missing from the font
|
2013-01-04 18:35:37 +00:00
|
|
|
aShapedText->SetMissingGlyph(aOffset, ch, this);
|
2008-08-06 20:48:55 +00:00
|
|
|
} else {
|
|
|
|
gfxTextRun::DetailedGlyph details;
|
|
|
|
details.mGlyphID = gid;
|
2013-01-04 18:35:37 +00:00
|
|
|
NS_ASSERTION(details.mGlyphID == gid,
|
|
|
|
"Seriously weird glyph ID detected!");
|
2008-08-06 20:48:55 +00:00
|
|
|
details.mAdvance = advance;
|
2013-01-04 18:35:37 +00:00
|
|
|
gfxShapedText::CompressedGlyph g;
|
|
|
|
g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1);
|
|
|
|
aShapedText->SetGlyphs(aOffset, g, &details);
|
2008-08-06 20:48:55 +00:00
|
|
|
}
|
|
|
|
}
|
2009-09-10 20:52:40 +00:00
|
|
|
}
|
2008-08-06 20:48:55 +00:00
|
|
|
|
2017-08-07 20:20:44 +00:00
|
|
|
gfxFT2Font::gfxFT2Font(const RefPtr<UnscaledFontFreeType>& aUnscaledFont,
|
2017-04-06 21:41:02 +00:00
|
|
|
cairo_scaled_font_t *aCairoFont,
|
2011-09-23 11:16:13 +00:00
|
|
|
FT2FontEntry *aFontEntry,
|
2011-07-26 14:04:55 +00:00
|
|
|
const gfxFontStyle *aFontStyle,
|
2011-09-29 06:19:26 +00:00
|
|
|
bool aNeedsBold)
|
2017-04-06 21:41:02 +00:00
|
|
|
: gfxFT2FontBase(aUnscaledFont, aCairoFont, aFontEntry, aFontStyle)
|
2014-08-06 13:31:21 +00:00
|
|
|
, mCharGlyphCache(32)
|
2008-08-06 20:48:55 +00:00
|
|
|
{
|
2008-08-28 11:05:53 +00:00
|
|
|
NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack.");
|
2011-09-02 20:18:25 +00:00
|
|
|
mApplySyntheticBold = aNeedsBold;
|
2008-08-06 20:48:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gfxFT2Font::~gfxFT2Font()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-08-07 20:20:44 +00:00
|
|
|
already_AddRefed<ScaledFont>
|
|
|
|
gfxFT2Font::GetScaledFont(DrawTarget *aTarget)
|
|
|
|
{
|
|
|
|
if (!mAzureScaledFont) {
|
|
|
|
NativeFont nativeFont;
|
|
|
|
nativeFont.mType = NativeFontType::CAIRO_FONT_FACE;
|
|
|
|
nativeFont.mFont = GetCairoScaledFont();
|
|
|
|
mAzureScaledFont =
|
|
|
|
Factory::CreateScaledFontForNativeFont(nativeFont,
|
|
|
|
GetUnscaledFont(),
|
|
|
|
GetAdjustedSize());
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<ScaledFont> scaledFont(mAzureScaledFont);
|
|
|
|
return scaledFont.forget();
|
|
|
|
}
|
|
|
|
|
2009-09-10 20:52:40 +00:00
|
|
|
void
|
2017-07-27 03:24:48 +00:00
|
|
|
gfxFT2Font::FillGlyphDataForChar(FT_Face face, uint32_t ch, CachedGlyphData *gd)
|
2009-09-10 20:52:40 +00:00
|
|
|
{
|
2012-05-21 21:09:54 +00:00
|
|
|
if (!face->charmap || face->charmap->encoding != FT_ENCODING_UNICODE) {
|
|
|
|
FT_Select_Charmap(face, FT_ENCODING_UNICODE);
|
|
|
|
}
|
2009-09-10 20:52:40 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-02-08 22:52:57 +00:00
|
|
|
FT_Int32 flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
|
|
|
|
FT_LOAD_DEFAULT :
|
|
|
|
(FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
|
|
|
|
FT_Error err = FT_Load_Glyph(face, gid, flags);
|
2009-09-10 20:52:40 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2012-03-23 12:14:16 +00:00
|
|
|
|
|
|
|
void
|
2017-08-07 20:20:44 +00:00
|
|
|
gfxFT2Font::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
2013-10-15 02:19:47 +00:00
|
|
|
FontCacheSizes* aSizes) const
|
2012-03-23 12:14:16 +00:00
|
|
|
{
|
2013-10-15 02:19:47 +00:00
|
|
|
gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-23 12:14:16 +00:00
|
|
|
aSizes->mFontInstances +=
|
2015-07-29 08:50:52 +00:00
|
|
|
mCharGlyphCache.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
2012-03-23 12:14:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-08-07 20:20:44 +00:00
|
|
|
gfxFT2Font::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
2013-10-15 02:19:47 +00:00
|
|
|
FontCacheSizes* aSizes) const
|
2012-03-23 12:14:16 +00:00
|
|
|
{
|
|
|
|
aSizes->mFontInstances += aMallocSizeOf(this);
|
2013-10-15 02:19:47 +00:00
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-23 12:14:16 +00:00
|
|
|
}
|
2013-06-05 17:48:59 +00:00
|
|
|
|