mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 631479 (part 4) - implement gfxGraphiteShaper to handle text-shaping for graphite-enabled fonts. r=jdaggett
This commit is contained in:
parent
e24f640930
commit
164f1ffdde
@ -216,6 +216,12 @@ CPPSRCS = \
|
||||
gfxSharedImageSurface.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_GRAPHITE
|
||||
CPPSRCS += \
|
||||
gfxGraphiteShaper.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
# Are we targeting x86 or x64? If so, build gfxAlphaRecoverySSE2.cpp.
|
||||
ifneq (,$(INTEL_ARCHITECTURE))
|
||||
CPPSRCS += gfxAlphaRecoverySSE2.cpp
|
||||
|
150
gfx/thebes/genLanguageTagList.pl
Normal file
150
gfx/thebes/genLanguageTagList.pl
Normal file
@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla Foundation code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2009-2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Jonathan Kew <jfkthame@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
# This tool is used to prepare a list of valid language subtags from the
|
||||
# IANA registry (http://www.iana.org/assignments/language-subtag-registry).
|
||||
|
||||
# Run as
|
||||
#
|
||||
# perl genLanguageTagList.pl language-subtag-registry > gfxLanguageTagList.cpp
|
||||
#
|
||||
# where language-subtag-registry is a copy of the IANA registry file.
|
||||
|
||||
use strict;
|
||||
|
||||
my $timestamp = gmtime();
|
||||
print <<__END;
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Foundation code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Kew <jfkthame\@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Derived from the IANA language subtag registry by genLanguageTagList.pl.
|
||||
*
|
||||
* Created on $timestamp.
|
||||
*
|
||||
* * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
|
||||
*/
|
||||
|
||||
__END
|
||||
|
||||
my $isLanguage = 0;
|
||||
|
||||
while (<>) {
|
||||
# strip leading/trailing whitespace, if any
|
||||
chomp;
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
|
||||
# assume File-Date precedes the actual list;
|
||||
# record the date, and begin assignment to an array of valid tags
|
||||
if (m/^File-Date:\s*(.+)$/) {
|
||||
print "// Based on IANA registry dated $1\n\n";
|
||||
print "static const PRUint32 sLanguageTagList[] = {";
|
||||
next;
|
||||
}
|
||||
|
||||
if (m/^%%/) {
|
||||
$isLanguage = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
# we only care about records of type 'language'
|
||||
if (m/^Type:\s*(.+)$/) {
|
||||
$isLanguage = ($1 eq 'language');
|
||||
next;
|
||||
}
|
||||
|
||||
# append the tag to our string, with ";" as a delimiter
|
||||
if ($isLanguage && m/^Subtag:\s*([a-z]{2,3})\s*$/) {
|
||||
my $tagstr = $1;
|
||||
print "\n TRUETYPE_TAG(",
|
||||
join(",", map { $_ eq " " ? " 0 " : "'" . $_ . "'" } split(//, substr($tagstr . " ", 0, 4))),
|
||||
"), // ", $tagstr;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($isLanguage && m/^Description:\s*(.+)$/) {
|
||||
print " = $1";
|
||||
$isLanguage = 0; # only print first Description field
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
# at end of file, terminate our assignment to the array of tags
|
||||
print <<__END;
|
||||
|
||||
0x0 // end of language code list
|
||||
};
|
||||
|
||||
/*
|
||||
* * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
|
||||
*/
|
||||
__END
|
@ -38,6 +38,9 @@
|
||||
#include "gfxDWriteFonts.h"
|
||||
#include "gfxDWriteShaper.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#include "gfxGraphiteShaper.h"
|
||||
#endif
|
||||
#include "gfxDWriteFontList.h"
|
||||
#include "gfxContext.h"
|
||||
#include <dwrite.h>
|
||||
@ -151,6 +154,12 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
|
||||
|
||||
ComputeMetrics(anAAOption);
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (FontCanSupportGraphite()) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (FontCanSupportHarfBuzz()) {
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
|
@ -56,6 +56,9 @@
|
||||
#include "gfxFT2FontList.h"
|
||||
#include <locale.h>
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#include "gfxGraphiteShaper.h"
|
||||
#endif
|
||||
#include "gfxUnicodeProperties.h"
|
||||
#include "gfxAtoms.h"
|
||||
#include "nsTArray.h"
|
||||
@ -432,7 +435,20 @@ gfxFT2Font::InitTextRun(gfxContext *aContext,
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aRunScript)) {
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (FontCanSupportGraphite()) {
|
||||
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
if (!mGraphiteShaper) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
ok = mGraphiteShaper->InitTextRun(aContext, aTextRun, aString,
|
||||
aRunStart, aRunLength,
|
||||
aRunScript);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aRunScript)) {
|
||||
if (!mHarfBuzzShaper) {
|
||||
gfxFT2LockedFace face(this);
|
||||
mFUnitsConvFactor = face.XScale();
|
||||
|
@ -384,6 +384,16 @@ gfxFontEntry::ShareFontTableAndGetBlob(PRUint32 aTag,
|
||||
return entry->ShareTableAndGetBlob(*aBuffer, &mFontTableCache);
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
void
|
||||
gfxFontEntry::CheckForGraphiteTables()
|
||||
{
|
||||
AutoFallibleTArray<PRUint8,16384> buffer;
|
||||
mHasGraphiteTables =
|
||||
NS_SUCCEEDED(GetFontTable(TRUETYPE_TAG('S','i','l','f'), buffer));
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// class gfxFontFamily
|
||||
@ -1064,9 +1074,7 @@ gfxFont::gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
|
||||
mStyle(*aFontStyle),
|
||||
mAdjustedSize(0.0),
|
||||
mFUnitsConvFactor(0.0f),
|
||||
mAntialiasOption(anAAOption),
|
||||
mPlatformShaper(nsnull),
|
||||
mHarfBuzzShaper(nsnull)
|
||||
mAntialiasOption(anAAOption)
|
||||
{
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
++gFontCount;
|
||||
@ -1603,7 +1611,15 @@ gfxFont::InitTextRun(gfxContext *aContext,
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if (mHarfBuzzShaper && !aPreferPlatformShaping) {
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->InitTextRun(aContext, aTextRun, aString,
|
||||
aRunStart, aRunLength,
|
||||
aRunScript);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ok && mHarfBuzzShaper && !aPreferPlatformShaping) {
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aRunScript)) {
|
||||
ok = mHarfBuzzShaper->InitTextRun(aContext, aTextRun, aString,
|
||||
aRunStart, aRunLength,
|
||||
|
@ -212,6 +212,9 @@ public:
|
||||
mSymbolFont(false),
|
||||
mIgnoreGDEF(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
#ifdef MOZ_GRAPHITE
|
||||
mCheckedForGraphiteTables(false),
|
||||
#endif
|
||||
mHasCmapTable(false),
|
||||
mCmapInitialized(false),
|
||||
mUVSOffset(0), mUVSData(nsnull),
|
||||
@ -244,6 +247,16 @@ public:
|
||||
|
||||
virtual bool IsSymbolFont();
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
inline bool HasGraphiteTables() {
|
||||
if (!mCheckedForGraphiteTables) {
|
||||
CheckForGraphiteTables();
|
||||
mCheckedForGraphiteTables = true;
|
||||
}
|
||||
return mHasGraphiteTables;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool HasCmapTable() {
|
||||
if (!mCmapInitialized) {
|
||||
ReadCMAP();
|
||||
@ -318,6 +331,10 @@ public:
|
||||
PRUint16 mWeight;
|
||||
PRInt16 mStretch;
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
bool mHasGraphiteTables;
|
||||
bool mCheckedForGraphiteTables;
|
||||
#endif
|
||||
bool mHasCmapTable;
|
||||
bool mCmapInitialized;
|
||||
gfxSparseBitSet mCharacterMap;
|
||||
@ -345,6 +362,9 @@ protected:
|
||||
mSymbolFont(false),
|
||||
mIgnoreGDEF(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
#ifdef MOZ_GRAPHITE
|
||||
mCheckedForGraphiteTables(false),
|
||||
#endif
|
||||
mHasCmapTable(false),
|
||||
mCmapInitialized(false),
|
||||
mUVSOffset(0), mUVSData(nsnull),
|
||||
@ -358,6 +378,10 @@ protected:
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
virtual void CheckForGraphiteTables();
|
||||
#endif
|
||||
|
||||
gfxFontFamily *mFamily;
|
||||
|
||||
private:
|
||||
@ -1004,6 +1028,13 @@ public:
|
||||
return mFontEntry->HasCmapTable();
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
// check whether this is an sfnt we can potentially use with Graphite
|
||||
bool FontCanSupportGraphite() {
|
||||
return mFontEntry->HasGraphiteTables();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Access to raw font table data (needed for Harfbuzz):
|
||||
// returns a pointer to data owned by the fontEntry or the OS,
|
||||
// which will remain valid until released.
|
||||
@ -1252,6 +1283,9 @@ protected:
|
||||
// of the text run being shaped
|
||||
nsAutoPtr<gfxFontShaper> mPlatformShaper;
|
||||
nsAutoPtr<gfxFontShaper> mHarfBuzzShaper;
|
||||
#ifdef MOZ_GRAPHITE
|
||||
nsAutoPtr<gfxFontShaper> mGraphiteShaper;
|
||||
#endif
|
||||
|
||||
// Create a default platform text shaper for this font.
|
||||
// (TODO: This should become pure virtual once all font backends have
|
||||
|
@ -43,6 +43,9 @@
|
||||
#include "gfxGDIShaper.h"
|
||||
#include "gfxUniscribeShaper.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#include "gfxGraphiteShaper.h"
|
||||
#endif
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxUnicodeProperties.h"
|
||||
@ -79,6 +82,11 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry,
|
||||
mSpaceGlyph(0),
|
||||
mNeedsBold(aNeedsBold)
|
||||
{
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (FontCanSupportGraphite()) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
#endif
|
||||
if (FontCanSupportHarfBuzz()) {
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
@ -159,7 +167,15 @@ gfxGDIFont::InitTextRun(gfxContext *aContext,
|
||||
// creating a "toy" font internally (see bug 544617)
|
||||
SetupCairoFont(aContext);
|
||||
|
||||
if (mHarfBuzzShaper) {
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->InitTextRun(aContext, aTextRun, aString,
|
||||
aRunStart, aRunLength,
|
||||
aRunScript);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ok && mHarfBuzzShaper) {
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aRunScript)) {
|
||||
ok = mHarfBuzzShaper->InitTextRun(aContext, aTextRun, aString,
|
||||
aRunStart, aRunLength,
|
||||
|
478
gfx/thebes/gfxGraphiteShaper.cpp
Normal file
478
gfx/thebes/gfxGraphiteShaper.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Graphite integration code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Kew <jfkthame@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "prmem.h"
|
||||
#include "nsString.h"
|
||||
#include "nsBidiUtils.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include "nsHashSets.h"
|
||||
|
||||
#include "gfxTypes.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxGraphiteShaper.h"
|
||||
#include "gfxFontUtils.h"
|
||||
#include "gfxUnicodeProperties.h"
|
||||
|
||||
#include "graphite2/Font.h"
|
||||
#include "graphite2/Segment.h"
|
||||
|
||||
#include "harfbuzz/hb-blob.h"
|
||||
|
||||
#include "cairo.h"
|
||||
|
||||
#include "nsUnicodeRange.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#define FloatToFixed(f) (65536 * (f))
|
||||
#define FixedToFloat(f) ((f) * (1.0 / 65536.0))
|
||||
// Right shifts of negative (signed) integers are undefined, as are overflows
|
||||
// when converting unsigned to negative signed integers.
|
||||
// (If speed were an issue we could make some 2's complement assumptions.)
|
||||
#define FixedToIntRound(f) ((f) > 0 ? ((32768 + (f)) >> 16) \
|
||||
: -((32767 - (f)) >> 16))
|
||||
|
||||
using namespace mozilla; // for AutoSwap_* types
|
||||
|
||||
/*
|
||||
* Creation and destruction; on deletion, release any font tables we're holding
|
||||
*/
|
||||
|
||||
gfxGraphiteShaper::gfxGraphiteShaper(gfxFont *aFont)
|
||||
: gfxFontShaper(aFont),
|
||||
mGrFace(nsnull),
|
||||
mGrFont(nsnull),
|
||||
mUseFontGlyphWidths(false)
|
||||
{
|
||||
mTables.Init();
|
||||
mCallbackData.mFont = aFont;
|
||||
mCallbackData.mShaper = this;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
ReleaseTableFunc(const PRUint32& /* aKey */,
|
||||
gfxGraphiteShaper::TableRec& aData,
|
||||
void* /* aUserArg */)
|
||||
{
|
||||
hb_blob_unlock(aData.mBlob);
|
||||
hb_blob_destroy(aData.mBlob);
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
gfxGraphiteShaper::~gfxGraphiteShaper()
|
||||
{
|
||||
if (mGrFont) {
|
||||
gr_font_destroy(mGrFont);
|
||||
}
|
||||
if (mGrFace) {
|
||||
gr_face_destroy(mGrFace);
|
||||
}
|
||||
mTables.Enumerate(ReleaseTableFunc, nsnull);
|
||||
}
|
||||
|
||||
static const void*
|
||||
GrGetTable(const void* appFaceHandle, unsigned int name, size_t *len)
|
||||
{
|
||||
const gfxGraphiteShaper::CallbackData *cb =
|
||||
static_cast<const gfxGraphiteShaper::CallbackData*>(appFaceHandle);
|
||||
return cb->mShaper->GetTable(name, len);
|
||||
}
|
||||
|
||||
const void*
|
||||
gfxGraphiteShaper::GetTable(PRUint32 aTag, size_t *aLength)
|
||||
{
|
||||
TableRec tableRec;
|
||||
|
||||
if (!mTables.Get(aTag, &tableRec)) {
|
||||
hb_blob_t *blob = mFont->GetFontTable(aTag);
|
||||
if (blob) {
|
||||
// mFont->GetFontTable() gives us a reference to the blob.
|
||||
// We will destroy (release) it in our destructor.
|
||||
// Meanwhile, we hold the blob locked because Graphite expects
|
||||
// the table pointer to remain valid for the life of the face.
|
||||
tableRec.mBlob = blob;
|
||||
tableRec.mData = hb_blob_lock(blob);
|
||||
tableRec.mLength = hb_blob_get_length(blob);
|
||||
mTables.Put(aTag, tableRec);
|
||||
} else {
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
*aLength = tableRec.mLength;
|
||||
return tableRec.mData;
|
||||
}
|
||||
|
||||
static float
|
||||
GrGetAdvance(const void* appFontHandle, gr_uint16 glyphid)
|
||||
{
|
||||
const gfxGraphiteShaper::CallbackData *cb =
|
||||
static_cast<const gfxGraphiteShaper::CallbackData*>(appFontHandle);
|
||||
return FixedToFloat(cb->mFont->GetGlyphWidth(cb->mContext, glyphid));
|
||||
}
|
||||
|
||||
static inline PRUint32
|
||||
MakeGraphiteLangTag(PRUint32 aTag)
|
||||
{
|
||||
PRUint32 grLangTag = aTag;
|
||||
// replace trailing space-padding with NULs for graphite
|
||||
PRUint32 mask = 0x000000FF;
|
||||
while ((grLangTag & mask) == ' ') {
|
||||
grLangTag &= ~mask;
|
||||
mask <<= 8;
|
||||
}
|
||||
return grLangTag;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxGraphiteShaper::InitTextRun(gfxContext *aContext,
|
||||
gfxTextRun *aTextRun,
|
||||
const PRUnichar *aString,
|
||||
PRUint32 aRunStart,
|
||||
PRUint32 aRunLength,
|
||||
PRInt32 aRunScript)
|
||||
{
|
||||
// some font back-ends require this in order to get proper hinted metrics
|
||||
mFont->SetupCairoFont(aContext);
|
||||
|
||||
mCallbackData.mContext = aContext;
|
||||
|
||||
if (!mGrFont) {
|
||||
mGrFace = gr_make_face(&mCallbackData, GrGetTable, gr_face_default);
|
||||
if (!mGrFace) {
|
||||
return false;
|
||||
}
|
||||
mGrFont = mUseFontGlyphWidths ?
|
||||
gr_make_font_with_advance_fn(mFont->GetAdjustedSize(),
|
||||
&mCallbackData, GrGetAdvance,
|
||||
mGrFace) :
|
||||
gr_make_font(mFont->GetAdjustedSize(), mGrFace);
|
||||
if (!mGrFont) {
|
||||
gr_face_destroy(mGrFace);
|
||||
mGrFace = nsnull;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const gfxFontStyle *style = aTextRun->GetFontGroup()->GetStyle();
|
||||
PRUint32 grLang = 0;
|
||||
if (style->languageOverride) {
|
||||
grLang = MakeGraphiteLangTag(style->languageOverride);
|
||||
} else if (mFont->GetFontEntry()->mLanguageOverride) {
|
||||
grLang = MakeGraphiteLangTag(mFont->GetFontEntry()->mLanguageOverride);
|
||||
} else {
|
||||
nsCAutoString langString;
|
||||
style->language->ToUTF8String(langString);
|
||||
grLang = GetGraphiteTagForLang(langString);
|
||||
}
|
||||
gr_feature_val *grFeatures = gr_face_featureval_for_lang(mGrFace, grLang);
|
||||
|
||||
bool disableLigatures =
|
||||
(aTextRun->GetFlags() &
|
||||
gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) != 0;
|
||||
if (disableLigatures) {
|
||||
const gr_feature_ref* fref =
|
||||
gr_face_find_fref(mGrFace, TRUETYPE_TAG('l','i','g','a'));
|
||||
if (fref) {
|
||||
gr_fref_set_feature_value(fref, 0, grFeatures);
|
||||
}
|
||||
}
|
||||
|
||||
const nsTArray<gfxFontFeature> *features = &style->featureSettings;
|
||||
if (features->IsEmpty()) {
|
||||
features = &mFont->GetFontEntry()->mFeatureSettings;
|
||||
}
|
||||
for (PRUint32 i = 0; i < features->Length(); ++i) {
|
||||
const gr_feature_ref* fref =
|
||||
gr_face_find_fref(mGrFace, (*features)[i].mTag);
|
||||
if (fref) {
|
||||
gr_fref_set_feature_value(fref, (*features)[i].mValue, grFeatures);
|
||||
}
|
||||
}
|
||||
|
||||
const PRUnichar *textStart = aString + aRunStart;
|
||||
const PRUnichar *textEnd = textStart + aRunLength;
|
||||
const void *pError;
|
||||
size_t nChars = gr_count_unicode_characters(gr_utf16,
|
||||
textStart, textEnd,
|
||||
&pError);
|
||||
if (pError != nsnull) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gr_segment *seg = gr_make_seg(mGrFont, mGrFace, 0, grFeatures,
|
||||
gr_utf16, textStart, nChars,
|
||||
aTextRun->IsRightToLeft());
|
||||
if (features) {
|
||||
gr_featureval_destroy(grFeatures);
|
||||
}
|
||||
if (!seg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = SetGlyphsFromSegment(aTextRun, aRunStart, aRunLength, seg);
|
||||
|
||||
gr_seg_destroy(seg);
|
||||
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
#define SMALL_GLYPH_RUN 256 // avoid heap allocation of per-glyph data arrays
|
||||
// for short (typical) runs up to this length
|
||||
|
||||
struct Cluster {
|
||||
PRUint32 baseChar;
|
||||
PRUint32 baseGlyph;
|
||||
PRUint32 nChars;
|
||||
PRUint32 nGlyphs;
|
||||
Cluster() : baseChar(0), baseGlyph(0), nChars(0), nGlyphs(0) { }
|
||||
};
|
||||
|
||||
nsresult
|
||||
gfxGraphiteShaper::SetGlyphsFromSegment(gfxTextRun *aTextRun,
|
||||
PRUint32 aRunStart,
|
||||
PRUint32 aRunLength,
|
||||
gr_segment *aSegment)
|
||||
{
|
||||
PRInt32 dev2appUnits = aTextRun->GetAppUnitsPerDevUnit();
|
||||
bool rtl = aTextRun->IsRightToLeft();
|
||||
|
||||
PRUint32 glyphCount = gr_seg_n_slots(aSegment);
|
||||
|
||||
// identify clusters; graphite may have reordered/expanded/ligated glyphs.
|
||||
nsAutoTArray<Cluster,SMALL_GLYPH_RUN> clusters;
|
||||
nsAutoTArray<PRUint16,SMALL_GLYPH_RUN> gids;
|
||||
nsAutoTArray<float,SMALL_GLYPH_RUN> xLocs;
|
||||
nsAutoTArray<float,SMALL_GLYPH_RUN> yLocs;
|
||||
|
||||
if (!clusters.SetLength(aRunLength) ||
|
||||
!gids.SetLength(glyphCount) ||
|
||||
!xLocs.SetLength(glyphCount) ||
|
||||
!yLocs.SetLength(glyphCount))
|
||||
{
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// walk through the glyph slots and check which original character
|
||||
// each is associated with
|
||||
PRUint32 gIndex = 0; // glyph slot index
|
||||
PRUint32 cIndex = 0; // current cluster index
|
||||
for (const gr_slot *slot = gr_seg_first_slot(aSegment);
|
||||
slot != nsnull;
|
||||
slot = gr_slot_next_in_segment(slot), gIndex++)
|
||||
{
|
||||
PRUint32 before = gr_slot_before(slot);
|
||||
PRUint32 after = gr_slot_after(slot);
|
||||
gids[gIndex] = gr_slot_gid(slot);
|
||||
xLocs[gIndex] = gr_slot_origin_X(slot);
|
||||
yLocs[gIndex] = gr_slot_origin_Y(slot);
|
||||
|
||||
// if this glyph has a "before" character index that precedes the
|
||||
// current cluster's char index, we need to merge preceding
|
||||
// clusters until it gets included
|
||||
while (before < clusters[cIndex].baseChar && cIndex > 0) {
|
||||
clusters[cIndex-1].nChars += clusters[cIndex].nChars;
|
||||
clusters[cIndex-1].nGlyphs += clusters[cIndex].nGlyphs;
|
||||
--cIndex;
|
||||
}
|
||||
|
||||
// if there's a gap between the current cluster's base character and
|
||||
// this glyph's, extend the cluster to include the intervening chars
|
||||
if (gr_slot_can_insert_before(slot) && clusters[cIndex].nChars &&
|
||||
before >= clusters[cIndex].baseChar + clusters[cIndex].nChars)
|
||||
{
|
||||
NS_ASSERTION(cIndex < aRunLength - 1, "cIndex at end of run");
|
||||
Cluster& c = clusters[cIndex + 1];
|
||||
c.baseChar = clusters[cIndex].baseChar + clusters[cIndex].nChars;
|
||||
c.nChars = before - c.baseChar;
|
||||
c.baseGlyph = gIndex;
|
||||
c.nGlyphs = 0;
|
||||
++cIndex;
|
||||
}
|
||||
|
||||
// increment cluster's glyph count to include current slot
|
||||
NS_ASSERTION(cIndex < aRunLength, "cIndex beyond valid run length");
|
||||
++clusters[cIndex].nGlyphs;
|
||||
|
||||
// extend cluster if necessary to reach the glyph's "after" index
|
||||
if (clusters[cIndex].baseChar + clusters[cIndex].nChars < after + 1) {
|
||||
clusters[cIndex].nChars = after + 1 - clusters[cIndex].baseChar;
|
||||
}
|
||||
}
|
||||
|
||||
// now put glyphs into the textrun, one cluster at a time
|
||||
for (PRUint32 i = 0; i <= cIndex; ++i) {
|
||||
const Cluster& c = clusters[i];
|
||||
|
||||
float adv; // total advance of the cluster
|
||||
if (rtl) {
|
||||
if (i == 0) {
|
||||
adv = gr_seg_advance_X(aSegment) - xLocs[c.baseGlyph];
|
||||
} else {
|
||||
adv = xLocs[clusters[i-1].baseGlyph] - xLocs[c.baseGlyph];
|
||||
}
|
||||
} else {
|
||||
if (i == cIndex) {
|
||||
adv = gr_seg_advance_X(aSegment) - xLocs[c.baseGlyph];
|
||||
} else {
|
||||
adv = xLocs[clusters[i+1].baseGlyph] - xLocs[c.baseGlyph];
|
||||
}
|
||||
}
|
||||
|
||||
// Check for default-ignorable char that didn't get filtered, combined,
|
||||
// etc by the shaping process, and skip it.
|
||||
PRUint32 offs = gr_cinfo_base(gr_seg_cinfo(aSegment, c.baseChar));
|
||||
NS_ASSERTION(offs >= c.baseChar && offs < aRunLength,
|
||||
"unexpected offset");
|
||||
if (c.nGlyphs == 1 && c.nChars == 1 &&
|
||||
aTextRun->FilterIfIgnorable(aRunStart + offs))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PRUint32 appAdvance = adv * dev2appUnits;
|
||||
if (c.nGlyphs == 1 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(appAdvance) &&
|
||||
yLocs[c.baseGlyph] == 0)
|
||||
{
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
aTextRun->SetSimpleGlyph(aRunStart + offs,
|
||||
g.SetSimpleGlyph(appAdvance,
|
||||
gids[c.baseGlyph]));
|
||||
} else {
|
||||
// not a one-to-one mapping with simple metrics: use DetailedGlyph
|
||||
nsAutoTArray<gfxTextRun::DetailedGlyph,8> details;
|
||||
float clusterLoc;
|
||||
for (PRUint32 j = c.baseGlyph; j < c.baseGlyph + c.nGlyphs; ++j) {
|
||||
gfxTextRun::DetailedGlyph* d = details.AppendElement();
|
||||
d->mGlyphID = gids[j];
|
||||
d->mYOffset = -yLocs[j] * dev2appUnits;
|
||||
if (j == c.baseGlyph) {
|
||||
d->mXOffset = 0;
|
||||
d->mAdvance = appAdvance;
|
||||
clusterLoc = xLocs[j];
|
||||
} else {
|
||||
d->mXOffset = (xLocs[j] - clusterLoc - adv) * dev2appUnits;
|
||||
d->mAdvance = 0;
|
||||
}
|
||||
}
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
g.SetComplex(aTextRun->IsClusterStart(aRunStart + offs),
|
||||
true, details.Length());
|
||||
aTextRun->SetGlyphs(aRunStart + offs, g, details.Elements());
|
||||
}
|
||||
|
||||
for (PRUint32 j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) {
|
||||
offs = gr_cinfo_base(gr_seg_cinfo(aSegment, j));
|
||||
NS_ASSERTION(offs >= j && offs < aRunLength,
|
||||
"unexpected offset");
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
g.SetComplex(aTextRun->IsClusterStart(aRunStart + offs),
|
||||
false, 0);
|
||||
aTextRun->SetGlyphs(aRunStart + offs, g, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// for language tag validation - include list of tags from the IANA registry
|
||||
#include "gfxLanguageTagList.cpp"
|
||||
|
||||
nsTHashtable<nsUint32HashKey> gfxGraphiteShaper::sLanguageTags;
|
||||
|
||||
/*static*/ PRUint32
|
||||
gfxGraphiteShaper::GetGraphiteTagForLang(const nsCString& aLang)
|
||||
{
|
||||
int len = aLang.Length();
|
||||
if (len < 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// convert primary language subtag to a left-packed, NUL-padded integer
|
||||
// for the Graphite API
|
||||
PRUint32 grLang = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
grLang <<= 8;
|
||||
if (i < len) {
|
||||
PRUint8 ch = aLang[i];
|
||||
if (ch == '-') {
|
||||
// found end of primary language subtag, truncate here
|
||||
len = i;
|
||||
continue;
|
||||
}
|
||||
if (ch < 'a' || ch > 'z') {
|
||||
// invalid character in tag, so ignore it completely
|
||||
return 0;
|
||||
}
|
||||
grLang += ch;
|
||||
}
|
||||
}
|
||||
|
||||
// valid tags must have length = 2 or 3
|
||||
if (len < 2 || len > 3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sLanguageTags.IsInitialized()) {
|
||||
// store the registered IANA tags in a hash for convenient validation
|
||||
sLanguageTags.Init(ArrayLength(sLanguageTagList));
|
||||
for (const PRUint32 *tag = sLanguageTagList; *tag != 0; ++tag) {
|
||||
sLanguageTags.PutEntry(*tag);
|
||||
}
|
||||
}
|
||||
|
||||
// only accept tags known in the IANA registry
|
||||
if (sLanguageTags.GetEntry(grLang)) {
|
||||
return grLang;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
gfxGraphiteShaper::Shutdown()
|
||||
{
|
||||
#ifdef NS_FREE_PERMANENT_DATA
|
||||
if (sLanguageTags.IsInitialized()) {
|
||||
sLanguageTags.Clear();
|
||||
}
|
||||
#endif
|
||||
}
|
100
gfx/thebes/gfxGraphiteShaper.h
Normal file
100
gfx/thebes/gfxGraphiteShaper.h
Normal file
@ -0,0 +1,100 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Graphite integration code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Kew <jfkthame@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef GFX_GRAPHITESHAPER_H
|
||||
#define GFX_GRAPHITESHAPER_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxFont.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
class gr_face;
|
||||
class gr_font;
|
||||
class gr_segment;
|
||||
|
||||
class gfxGraphiteShaper : public gfxFontShaper {
|
||||
public:
|
||||
gfxGraphiteShaper(gfxFont *aFont);
|
||||
virtual ~gfxGraphiteShaper();
|
||||
|
||||
virtual bool InitTextRun(gfxContext *aContext,
|
||||
gfxTextRun *aTextRun,
|
||||
const PRUnichar *aString,
|
||||
PRUint32 aRunStart,
|
||||
PRUint32 aRunLength,
|
||||
PRInt32 aRunScript);
|
||||
|
||||
const void* GetTable(PRUint32 aTag, size_t *aLength);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
struct CallbackData {
|
||||
gfxFont *mFont;
|
||||
gfxGraphiteShaper *mShaper;
|
||||
gfxContext *mContext;
|
||||
};
|
||||
|
||||
struct TableRec {
|
||||
hb_blob_t *mBlob;
|
||||
const void *mData;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsresult SetGlyphsFromSegment(gfxTextRun *aTextRun,
|
||||
PRUint32 aRunStart,
|
||||
PRUint32 aRunLength,
|
||||
gr_segment *aSegment);
|
||||
|
||||
gr_face *mGrFace;
|
||||
gr_font *mGrFont;
|
||||
|
||||
CallbackData mCallbackData;
|
||||
|
||||
nsDataHashtable<nsUint32HashKey,TableRec> mTables;
|
||||
|
||||
// Whether the font implements GetGlyphWidth, or we should read tables
|
||||
// directly to get ideal widths
|
||||
bool mUseFontGlyphWidths;
|
||||
|
||||
// Convert HTML 'lang' (BCP47) to Graphite language code
|
||||
static PRUint32 GetGraphiteTagForLang(const nsCString& aLang);
|
||||
static nsTHashtable<nsUint32HashKey> sLanguageTags;
|
||||
};
|
||||
|
||||
#endif /* GFX_GRAPHITESHAPER_H */
|
7908
gfx/thebes/gfxLanguageTagList.cpp
Normal file
7908
gfx/thebes/gfxLanguageTagList.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -41,6 +41,9 @@
|
||||
#include "gfxMacFont.h"
|
||||
#include "gfxCoreTextShaper.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#include "gfxGraphiteShaper.h"
|
||||
#endif
|
||||
#include "gfxPlatformMac.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxUnicodeProperties.h"
|
||||
@ -133,6 +136,11 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (FontCanSupportGraphite()) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
#endif
|
||||
if (FontCanSupportHarfBuzz()) {
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ ATSFontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray<PRUint8>& aBuffer)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!aBuffer.AppendElements(dataLength)) {
|
||||
if (!aBuffer.SetLength(dataLength)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
PRUint8 *dataPtr = aBuffer.Elements();
|
||||
|
@ -66,6 +66,9 @@
|
||||
#include "harfbuzz/hb-unicode.h"
|
||||
#include "harfbuzz/hb-ot-tag.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#include "gfxGraphiteShaper.h"
|
||||
#endif
|
||||
#include "gfxUnicodeProperties.h"
|
||||
#include "gfxFontconfigUtils.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
@ -229,6 +232,10 @@ protected:
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
virtual void CheckForGraphiteTables();
|
||||
#endif
|
||||
|
||||
// One pattern is the common case and some subclasses rely on successful
|
||||
// addition of the first element to the array.
|
||||
nsAutoTArray<nsCountedRef<FcPattern>,1> mPatterns;
|
||||
@ -280,6 +287,19 @@ gfxFcFontEntry::RealFaceName()
|
||||
return gfxFontEntry::RealFaceName();
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
void
|
||||
gfxFcFontEntry::CheckForGraphiteTables()
|
||||
{
|
||||
FcChar8 *capability;
|
||||
mHasGraphiteTables =
|
||||
!mPatterns.IsEmpty() &&
|
||||
FcPatternGetString(mPatterns[0],
|
||||
FC_CAPABILITY, 0, &capability) == FcResultMatch &&
|
||||
FcStrStr(capability, gfxFontconfigUtils::ToFcChar8("ttable:Silf"));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
gfxFcFontEntry::ShouldUseHarfBuzz(PRInt32 aRunScript) {
|
||||
if (mSkipHarfBuzz ||
|
||||
@ -2192,6 +2212,21 @@ gfxFcFont::InitTextRun(gfxContext *aContext,
|
||||
{
|
||||
gfxFcFontEntry *fontEntry = static_cast<gfxFcFontEntry*>(GetFontEntry());
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
if (FontCanSupportGraphite()) {
|
||||
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
if (!mGraphiteShaper) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
if (mGraphiteShaper->InitTextRun(aContext, aTextRun, aString,
|
||||
aRunStart, aRunLength,
|
||||
aRunScript)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fontEntry->ShouldUseHarfBuzz(aRunScript)) {
|
||||
if (!mHarfBuzzShaper) {
|
||||
gfxFT2LockedFace face(this);
|
||||
|
@ -66,6 +66,9 @@
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "gfxUnicodeProperties.h"
|
||||
#include "harfbuzz/hb-unicode.h"
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#include "gfxGraphiteShaper.h"
|
||||
#endif
|
||||
|
||||
#include "nsUnicodeRange.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
@ -150,6 +153,10 @@ SRGBOverrideObserver::Observe(nsISupports *aSubject,
|
||||
#define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
|
||||
#define HARFBUZZ_SCRIPTS_DEFAULT gfxUnicodeProperties::SHAPING_DEFAULT
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
|
||||
#endif
|
||||
|
||||
static const char* kObservedPrefs[] = {
|
||||
"gfx.downloadable_fonts.",
|
||||
"gfx.font_rendering.",
|
||||
@ -225,6 +232,9 @@ gfxPlatform::gfxPlatform()
|
||||
mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
|
||||
mAllowDownloadableFonts = UNINITIALIZED_VALUE;
|
||||
mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
|
||||
#ifdef MOZ_GRAPHITE
|
||||
mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
gfxPlatform*
|
||||
@ -337,6 +347,9 @@ gfxPlatform::Shutdown()
|
||||
gfxTextRunWordCache::Shutdown();
|
||||
gfxFontCache::Shutdown();
|
||||
gfxFontGroup::Shutdown();
|
||||
#ifdef MOZ_GRAPHITE
|
||||
gfxGraphiteShaper::Shutdown();
|
||||
#endif
|
||||
#if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
|
||||
gfxPlatformFontList::Shutdown();
|
||||
#endif
|
||||
@ -590,6 +603,19 @@ gfxPlatform::SanitizeDownloadedFonts()
|
||||
return mDownloadableFontsSanitize;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
bool
|
||||
gfxPlatform::UseGraphiteShaping()
|
||||
{
|
||||
if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
|
||||
mGraphiteShapingEnabled =
|
||||
Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
|
||||
}
|
||||
|
||||
return mGraphiteShapingEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
gfxPlatform::UseHarfBuzzForScript(PRInt32 aScriptCode)
|
||||
{
|
||||
@ -1329,6 +1355,12 @@ gfxPlatform::FontsPrefsChanged(const char *aPref)
|
||||
mAllowDownloadableFonts = UNINITIALIZED_VALUE;
|
||||
} else if (!strcmp(GFX_DOWNLOADABLE_FONTS_SANITIZE, aPref)) {
|
||||
mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
|
||||
#ifdef MOZ_GRAPHITE
|
||||
} else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
|
||||
mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
|
||||
gfxTextRunWordCache::Flush();
|
||||
gfxFontCache::GetCache()->AgeAllGenerations();
|
||||
#endif
|
||||
} else if (!strcmp(GFX_PREF_HARFBUZZ_SCRIPTS, aPref)) {
|
||||
mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
|
||||
gfxTextRunWordCache::Flush();
|
||||
|
@ -305,6 +305,14 @@ public:
|
||||
*/
|
||||
bool SanitizeDownloadedFonts();
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
/**
|
||||
* Whether to use the SIL Graphite rendering engine
|
||||
* (for fonts that include Graphite tables)
|
||||
*/
|
||||
bool UseGraphiteShaping();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Whether to use the harfbuzz shaper (depending on script complexity).
|
||||
*
|
||||
@ -423,6 +431,9 @@ protected:
|
||||
|
||||
PRInt8 mAllowDownloadableFonts;
|
||||
PRInt8 mDownloadableFontsSanitize;
|
||||
#ifdef MOZ_GRAPHITE
|
||||
PRInt8 mGraphiteShapingEnabled;
|
||||
#endif
|
||||
|
||||
// which scripts should be shaped with harfbuzz
|
||||
PRInt32 mUseHarfBuzzScripts;
|
||||
|
@ -200,6 +200,10 @@ pref("gfx.downloadable_fonts.enabled", true);
|
||||
pref("gfx.downloadable_fonts.fallback_delay", 3000);
|
||||
pref("gfx.downloadable_fonts.sanitize", true);
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
pref("gfx.font_rendering.graphite.enabled", false);
|
||||
#endif
|
||||
|
||||
// see gfx/thebes/gfxUnicodeProperties.h for definitions of script bits
|
||||
#ifdef XP_MACOSX
|
||||
// use harfbuzz for default (0x01) + arabic (0x02) + hebrew (0x04) + thai (0x40)
|
||||
|
Loading…
Reference in New Issue
Block a user