зеркало из https://github.com/mozilla/gecko-dev.git
bug 1066043 - split gfxFont.cpp and .h into more manageably-sized pieces. r=jdaggett
--HG-- rename : gfx/thebes/gfxFont.cpp => gfx/thebes/gfxFontEntry.cpp rename : gfx/thebes/gfxFont.h => gfx/thebes/gfxFontEntry.h rename : gfx/thebes/gfxFont.cpp => gfx/thebes/gfxGlyphExtents.cpp rename : gfx/thebes/gfxFont.h => gfx/thebes/gfxGlyphExtents.h rename : gfx/thebes/gfxFont.cpp => gfx/thebes/gfxTextRun.cpp rename : gfx/thebes/gfxFont.h => gfx/thebes/gfxTextRun.h
This commit is contained in:
Родитель
cde8159f8a
Коммит
50b0ff2a5d
|
@ -6,7 +6,7 @@
|
|||
#include "nsLineBreaker.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsILineBreaker.h"
|
||||
#include "gfxFont.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values
|
||||
#include "gfxTextRun.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values
|
||||
#include "nsHyphenationManager.h"
|
||||
#include "nsHyphenator.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/dom/HTMLVideoElement.h"
|
||||
#include "CanvasUtils.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/CanvasGradient.h"
|
||||
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include <sys/types.h> // for int32_t
|
||||
#include "gfxFont.h" // for gfxFont, gfxFontGroup
|
||||
#include "gfxTextRun.h" // for gfxFont, gfxFontGroup
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "gfx2DGlue.h"
|
||||
#include "gfxFT2FontList.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsIScreen.h"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "gfxCoreTextShaper.h"
|
||||
#include "gfxMacFont.h"
|
||||
#include "gfxFontUtils.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <algorithm>
|
||||
#include "gfxDWriteFontList.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include <dwrite.h>
|
||||
|
||||
#include "harfbuzz/hb.h"
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "gfxFT2FontBase.h"
|
||||
#include "gfxFT2Utils.h"
|
||||
#include "gfxFT2FontList.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include <locale.h>
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsTArray.h"
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
3141
gfx/thebes/gfxFont.h
3141
gfx/thebes/gfxFont.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,819 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef GFX_FONTENTRY_H
|
||||
#define GFX_FONTENTRY_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
#include "nsString.h"
|
||||
#include "gfxFontFeatures.h"
|
||||
#include "gfxFontUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "DrawMode.h"
|
||||
#include "nsUnicodeScriptCodes.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
typedef struct gr_face gr_face;
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
struct gfxFontStyle;
|
||||
class gfxContext;
|
||||
class gfxFont;
|
||||
class gfxFontFamily;
|
||||
class gfxUserFontData;
|
||||
class gfxSVGGlyphs;
|
||||
class gfxMathTable;
|
||||
class gfxTextContextPaint;
|
||||
class FontInfoData;
|
||||
struct FontListSizes;
|
||||
class nsIAtom;
|
||||
|
||||
class gfxCharacterMap : public gfxSparseBitSet {
|
||||
public:
|
||||
nsrefcnt AddRef() {
|
||||
NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "gfxCharacterMap", sizeof(*this));
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
nsrefcnt Release() {
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "gfxCharacterMap");
|
||||
if (mRefCnt == 0) {
|
||||
NotifyReleased();
|
||||
// |this| has been deleted.
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
gfxCharacterMap() :
|
||||
mHash(0), mBuildOnTheFly(false), mShared(false)
|
||||
{ }
|
||||
|
||||
void CalcHash() { mHash = GetChecksum(); }
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||
return gfxSparseBitSet::SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
// hash of the cmap bitvector
|
||||
uint32_t mHash;
|
||||
|
||||
// if cmap is built on the fly it's never shared
|
||||
bool mBuildOnTheFly;
|
||||
|
||||
// cmap is shared globally
|
||||
bool mShared;
|
||||
|
||||
protected:
|
||||
void NotifyReleased();
|
||||
|
||||
nsAutoRefCnt mRefCnt;
|
||||
|
||||
private:
|
||||
gfxCharacterMap(const gfxCharacterMap&);
|
||||
gfxCharacterMap& operator=(const gfxCharacterMap&);
|
||||
};
|
||||
|
||||
class gfxFontEntry {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
|
||||
|
||||
explicit gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false);
|
||||
|
||||
// unique name for the face, *not* the family; not necessarily the
|
||||
// "real" or user-friendly name, may be an internal identifier
|
||||
const nsString& Name() const { return mName; }
|
||||
|
||||
// family name
|
||||
const nsString& FamilyName() const { return mFamilyName; }
|
||||
|
||||
// The following two methods may be relatively expensive, as they
|
||||
// will (usually, except on Linux) load and parse the 'name' table;
|
||||
// they are intended only for the font-inspection API, not for
|
||||
// perf-critical layout/drawing work.
|
||||
|
||||
// The "real" name of the face, if available from the font resource;
|
||||
// returns Name() if nothing better is available.
|
||||
virtual nsString RealFaceName();
|
||||
|
||||
uint16_t Weight() const { return mWeight; }
|
||||
int16_t Stretch() const { return mStretch; }
|
||||
|
||||
bool IsUserFont() const { return mIsDataUserFont || mIsLocalUserFont; }
|
||||
bool IsLocalUserFont() const { return mIsLocalUserFont; }
|
||||
bool IsFixedPitch() const { return mFixedPitch; }
|
||||
bool IsItalic() const { return mItalic; }
|
||||
bool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above
|
||||
bool IgnoreGDEF() const { return mIgnoreGDEF; }
|
||||
bool IgnoreGSUB() const { return mIgnoreGSUB; }
|
||||
|
||||
// whether a feature is supported by the font (limited to a small set
|
||||
// of features for which some form of fallback needs to be implemented)
|
||||
bool SupportsOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag);
|
||||
bool SupportsGraphiteFeature(uint32_t aFeatureTag);
|
||||
|
||||
// returns a set containing all input glyph ids for a given feature
|
||||
const hb_set_t*
|
||||
InputsForOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag);
|
||||
|
||||
virtual bool IsSymbolFont();
|
||||
|
||||
virtual bool HasFontTable(uint32_t aTableTag);
|
||||
|
||||
inline bool HasGraphiteTables() {
|
||||
if (!mCheckedForGraphiteTables) {
|
||||
CheckForGraphiteTables();
|
||||
mCheckedForGraphiteTables = true;
|
||||
}
|
||||
return mHasGraphiteTables;
|
||||
}
|
||||
|
||||
inline bool HasCmapTable() {
|
||||
if (!mCharacterMap) {
|
||||
ReadCMAP();
|
||||
NS_ASSERTION(mCharacterMap, "failed to initialize character map");
|
||||
}
|
||||
return mHasCmapTable;
|
||||
}
|
||||
|
||||
inline bool HasCharacter(uint32_t ch) {
|
||||
if (mCharacterMap && mCharacterMap->test(ch)) {
|
||||
return true;
|
||||
}
|
||||
return TestCharacterMap(ch);
|
||||
}
|
||||
|
||||
virtual bool SkipDuringSystemFallback() { return false; }
|
||||
virtual bool TestCharacterMap(uint32_t aCh);
|
||||
nsresult InitializeUVSMap();
|
||||
uint16_t GetUVSGlyph(uint32_t aCh, uint32_t aVS);
|
||||
|
||||
// All concrete gfxFontEntry subclasses (except gfxUserFontEntry) need
|
||||
// to override this, otherwise the font will never be used as it will
|
||||
// be considered to support no characters.
|
||||
// ReadCMAP() must *always* set the mCharacterMap pointer to a valid
|
||||
// gfxCharacterMap, even if empty, as other code assumes this pointer
|
||||
// can be safely dereferenced.
|
||||
virtual nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
|
||||
|
||||
bool TryGetSVGData(gfxFont* aFont);
|
||||
bool HasSVGGlyph(uint32_t aGlyphId);
|
||||
bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
|
||||
gfxRect *aResult);
|
||||
bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode,
|
||||
gfxTextContextPaint *aContextPaint);
|
||||
// Call this when glyph geometry or rendering has changed
|
||||
// (e.g. animated SVG glyphs)
|
||||
void NotifyGlyphsChanged();
|
||||
|
||||
enum MathConstant {
|
||||
// The order of the constants must match the order of the fields
|
||||
// defined in the MATH table.
|
||||
ScriptPercentScaleDown,
|
||||
ScriptScriptPercentScaleDown,
|
||||
DelimitedSubFormulaMinHeight,
|
||||
DisplayOperatorMinHeight,
|
||||
MathLeading,
|
||||
AxisHeight,
|
||||
AccentBaseHeight,
|
||||
FlattenedAccentBaseHeight,
|
||||
SubscriptShiftDown,
|
||||
SubscriptTopMax,
|
||||
SubscriptBaselineDropMin,
|
||||
SuperscriptShiftUp,
|
||||
SuperscriptShiftUpCramped,
|
||||
SuperscriptBottomMin,
|
||||
SuperscriptBaselineDropMax,
|
||||
SubSuperscriptGapMin,
|
||||
SuperscriptBottomMaxWithSubscript,
|
||||
SpaceAfterScript,
|
||||
UpperLimitGapMin,
|
||||
UpperLimitBaselineRiseMin,
|
||||
LowerLimitGapMin,
|
||||
LowerLimitBaselineDropMin,
|
||||
StackTopShiftUp,
|
||||
StackTopDisplayStyleShiftUp,
|
||||
StackBottomShiftDown,
|
||||
StackBottomDisplayStyleShiftDown,
|
||||
StackGapMin,
|
||||
StackDisplayStyleGapMin,
|
||||
StretchStackTopShiftUp,
|
||||
StretchStackBottomShiftDown,
|
||||
StretchStackGapAboveMin,
|
||||
StretchStackGapBelowMin,
|
||||
FractionNumeratorShiftUp,
|
||||
FractionNumeratorDisplayStyleShiftUp,
|
||||
FractionDenominatorShiftDown,
|
||||
FractionDenominatorDisplayStyleShiftDown,
|
||||
FractionNumeratorGapMin,
|
||||
FractionNumDisplayStyleGapMin,
|
||||
FractionRuleThickness,
|
||||
FractionDenominatorGapMin,
|
||||
FractionDenomDisplayStyleGapMin,
|
||||
SkewedFractionHorizontalGap,
|
||||
SkewedFractionVerticalGap,
|
||||
OverbarVerticalGap,
|
||||
OverbarRuleThickness,
|
||||
OverbarExtraAscender,
|
||||
UnderbarVerticalGap,
|
||||
UnderbarRuleThickness,
|
||||
UnderbarExtraDescender,
|
||||
RadicalVerticalGap,
|
||||
RadicalDisplayStyleVerticalGap,
|
||||
RadicalRuleThickness,
|
||||
RadicalExtraAscender,
|
||||
RadicalKernBeforeDegree,
|
||||
RadicalKernAfterDegree,
|
||||
RadicalDegreeBottomRaisePercent
|
||||
};
|
||||
|
||||
// Call TryGetMathTable to try to load the Open Type MATH table. The other
|
||||
// functions forward the call to the gfxMathTable class. The GetMath...()
|
||||
// functions MUST NOT be called unless TryGetMathTable() has returned true.
|
||||
bool TryGetMathTable();
|
||||
gfxFloat GetMathConstant(MathConstant aConstant);
|
||||
bool GetMathItalicsCorrection(uint32_t aGlyphID,
|
||||
gfxFloat* aItalicCorrection);
|
||||
uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical,
|
||||
uint16_t aSize);
|
||||
bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical,
|
||||
uint32_t aGlyphs[4]);
|
||||
|
||||
bool TryGetColorGlyphs();
|
||||
bool GetColorLayersInfo(uint32_t aGlyphId,
|
||||
nsTArray<uint16_t>& layerGlyphs,
|
||||
nsTArray<mozilla::gfx::Color>& layerColors);
|
||||
|
||||
virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
|
||||
return true;
|
||||
}
|
||||
virtual bool SupportsLangGroup(nsIAtom *aLangGroup) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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 the blob is destroyed.
|
||||
// The data MUST be treated as read-only; we may be getting a
|
||||
// reference to a shared system font cache.
|
||||
//
|
||||
// The default implementation uses CopyFontTable to get the data
|
||||
// into a byte array, and maintains a cache of loaded tables.
|
||||
//
|
||||
// Subclasses should override this if they can provide more efficient
|
||||
// access than copying table data into our own buffers.
|
||||
//
|
||||
// Get blob that encapsulates a specific font table, or nullptr if
|
||||
// the table doesn't exist in the font.
|
||||
//
|
||||
// Caller is responsible to call hb_blob_destroy() on the returned blob
|
||||
// (if non-nullptr) when no longer required. For transient access to a
|
||||
// table, use of AutoTable (below) is generally preferred.
|
||||
virtual hb_blob_t *GetFontTable(uint32_t aTag);
|
||||
|
||||
// Stack-based utility to return a specified table, automatically releasing
|
||||
// the blob when the AutoTable goes out of scope.
|
||||
class AutoTable {
|
||||
public:
|
||||
AutoTable(gfxFontEntry* aFontEntry, uint32_t aTag)
|
||||
{
|
||||
mBlob = aFontEntry->GetFontTable(aTag);
|
||||
}
|
||||
~AutoTable() {
|
||||
if (mBlob) {
|
||||
hb_blob_destroy(mBlob);
|
||||
}
|
||||
}
|
||||
operator hb_blob_t*() const { return mBlob; }
|
||||
private:
|
||||
hb_blob_t* mBlob;
|
||||
// not implemented:
|
||||
AutoTable(const AutoTable&) MOZ_DELETE;
|
||||
AutoTable& operator=(const AutoTable&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
|
||||
bool aNeedsBold);
|
||||
|
||||
// Get an existing font table cache entry in aBlob if it has been
|
||||
// registered, or return false if not. Callers must call
|
||||
// hb_blob_destroy on aBlob if true is returned.
|
||||
//
|
||||
// Note that some gfxFont implementations may not call this at all,
|
||||
// if it is more efficient to get the table from the OS at that level.
|
||||
bool GetExistingFontTable(uint32_t aTag, hb_blob_t** aBlob);
|
||||
|
||||
// Elements of aTable are transferred (not copied) to and returned in a
|
||||
// new hb_blob_t which is registered on the gfxFontEntry, but the initial
|
||||
// reference is owned by the caller. Removing the last reference
|
||||
// unregisters the table from the font entry.
|
||||
//
|
||||
// Pass nullptr for aBuffer to indicate that the table is not present and
|
||||
// nullptr will be returned. Also returns nullptr on OOM.
|
||||
hb_blob_t *ShareFontTableAndGetBlob(uint32_t aTag,
|
||||
FallibleTArray<uint8_t>* aTable);
|
||||
|
||||
// Get the font's unitsPerEm from the 'head' table, in the case of an
|
||||
// sfnt resource. Will return kInvalidUPEM for non-sfnt fonts,
|
||||
// if present on the platform.
|
||||
uint16_t UnitsPerEm();
|
||||
enum {
|
||||
kMinUPEM = 16, // Limits on valid unitsPerEm range, from the
|
||||
kMaxUPEM = 16384, // OpenType spec
|
||||
kInvalidUPEM = uint16_t(-1)
|
||||
};
|
||||
|
||||
// Shaper face accessors:
|
||||
// NOTE that harfbuzz and graphite handle ownership/lifetime of the face
|
||||
// object in completely different ways.
|
||||
|
||||
// Get HarfBuzz face corresponding to this font file.
|
||||
// Caller must release with hb_face_destroy() when finished with it,
|
||||
// and the font entry will be notified via ForgetHBFace.
|
||||
hb_face_t* GetHBFace();
|
||||
virtual void ForgetHBFace();
|
||||
|
||||
// Get Graphite face corresponding to this font file.
|
||||
// Caller must call gfxFontEntry::ReleaseGrFace when finished with it.
|
||||
gr_face* GetGrFace();
|
||||
virtual void ReleaseGrFace(gr_face* aFace);
|
||||
|
||||
// Release any SVG-glyphs document this font may have loaded.
|
||||
void DisconnectSVG();
|
||||
|
||||
// Called to notify that aFont is being destroyed. Needed when we're tracking
|
||||
// the fonts belonging to this font entry.
|
||||
void NotifyFontDestroyed(gfxFont* aFont);
|
||||
|
||||
// For memory reporting
|
||||
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
|
||||
// Used when checking for complex script support, to mask off cmap ranges
|
||||
struct ScriptRange {
|
||||
uint32_t rangeStart;
|
||||
uint32_t rangeEnd;
|
||||
hb_tag_t tags[3]; // one or two OpenType script tags to check,
|
||||
// plus a NULL terminator
|
||||
};
|
||||
|
||||
bool SupportsScriptInGSUB(const hb_tag_t* aScriptTags);
|
||||
|
||||
nsString mName;
|
||||
nsString mFamilyName;
|
||||
|
||||
bool mItalic : 1;
|
||||
bool mFixedPitch : 1;
|
||||
bool mIsValid : 1;
|
||||
bool mIsBadUnderlineFont : 1;
|
||||
bool mIsUserFontContainer : 1; // userfont entry
|
||||
bool mIsDataUserFont : 1; // platform font entry (data)
|
||||
bool mIsLocalUserFont : 1; // platform font entry (local)
|
||||
bool mStandardFace : 1;
|
||||
bool mSymbolFont : 1;
|
||||
bool mIgnoreGDEF : 1;
|
||||
bool mIgnoreGSUB : 1;
|
||||
bool mSVGInitialized : 1;
|
||||
bool mMathInitialized : 1;
|
||||
bool mHasSpaceFeaturesInitialized : 1;
|
||||
bool mHasSpaceFeatures : 1;
|
||||
bool mHasSpaceFeaturesKerning : 1;
|
||||
bool mHasSpaceFeaturesNonKerning : 1;
|
||||
bool mSkipDefaultFeatureSpaceCheck : 1;
|
||||
bool mHasGraphiteTables : 1;
|
||||
bool mCheckedForGraphiteTables : 1;
|
||||
bool mHasCmapTable : 1;
|
||||
bool mGrFaceInitialized : 1;
|
||||
bool mCheckedForColorGlyph : 1;
|
||||
|
||||
// bitvector of substitution space features per script, one each
|
||||
// for default and non-default features
|
||||
uint32_t mDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
|
||||
uint32_t mNonDefaultSubSpaceFeatures[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
|
||||
|
||||
uint16_t mWeight;
|
||||
int16_t mStretch;
|
||||
|
||||
nsRefPtr<gfxCharacterMap> mCharacterMap;
|
||||
uint32_t mUVSOffset;
|
||||
nsAutoArrayPtr<uint8_t> mUVSData;
|
||||
nsAutoPtr<gfxUserFontData> mUserFontData;
|
||||
nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
|
||||
// list of gfxFonts that are using SVG glyphs
|
||||
nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
|
||||
nsAutoPtr<gfxMathTable> mMathTable;
|
||||
nsTArray<gfxFontFeature> mFeatureSettings;
|
||||
nsAutoPtr<nsDataHashtable<nsUint32HashKey,bool>> mSupportedFeatures;
|
||||
nsAutoPtr<nsDataHashtable<nsUint32HashKey,hb_set_t*>> mFeatureInputs;
|
||||
uint32_t mLanguageOverride;
|
||||
|
||||
// Color Layer font support
|
||||
hb_blob_t* mCOLR;
|
||||
hb_blob_t* mCPAL;
|
||||
|
||||
protected:
|
||||
friend class gfxPlatformFontList;
|
||||
friend class gfxMacPlatformFontList;
|
||||
friend class gfxUserFcFontEntry;
|
||||
friend class gfxFontFamily;
|
||||
friend class gfxSingleFaceMacFontFamily;
|
||||
|
||||
gfxFontEntry();
|
||||
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
virtual ~gfxFontEntry();
|
||||
|
||||
virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) {
|
||||
NS_NOTREACHED("oops, somebody didn't override CreateFontInstance");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void CheckForGraphiteTables();
|
||||
|
||||
// Copy a font table into aBuffer.
|
||||
// The caller will be responsible for ownership of the data.
|
||||
virtual nsresult CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer) {
|
||||
NS_NOTREACHED("forgot to override either GetFontTable or CopyFontTable?");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Return a blob that wraps a table found within a buffer of font data.
|
||||
// The blob does NOT own its data; caller guarantees that the buffer
|
||||
// will remain valid at least as long as the blob.
|
||||
// Returns null if the specified table is not found.
|
||||
// This method assumes aFontData is valid 'sfnt' data; before using this,
|
||||
// caller is responsible to do any sanitization/validation necessary.
|
||||
hb_blob_t* GetTableFromFontData(const void* aFontData, uint32_t aTableTag);
|
||||
|
||||
// lookup the cmap in cached font data
|
||||
virtual already_AddRefed<gfxCharacterMap>
|
||||
GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
|
||||
uint32_t& aUVSOffset,
|
||||
bool& aSymbolFont);
|
||||
|
||||
// Font's unitsPerEm from the 'head' table, if available (will be set to
|
||||
// kInvalidUPEM for non-sfnt font formats)
|
||||
uint16_t mUnitsPerEm;
|
||||
|
||||
// Shaper-specific face objects, shared by all instantiations of the same
|
||||
// physical font, regardless of size.
|
||||
// Usually, only one of these will actually be created for any given font
|
||||
// entry, depending on the font tables that are present.
|
||||
|
||||
// hb_face_t is refcounted internally, so each shaper that's using it will
|
||||
// bump the ref count when it acquires the face, and "destroy" (release) it
|
||||
// in its destructor. The font entry has only this non-owning reference to
|
||||
// the face; when the face is deleted, it will tell the font entry to forget
|
||||
// it, so that a new face will be created next time it is needed.
|
||||
hb_face_t* mHBFace;
|
||||
|
||||
static hb_blob_t* HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData);
|
||||
|
||||
// Callback that the hb_face will use to tell us when it is being deleted.
|
||||
static void HBFaceDeletedCallback(void *aUserData);
|
||||
|
||||
// gr_face is -not- refcounted, so it will be owned directly by the font
|
||||
// entry, and we'll keep a count of how many references we've handed out;
|
||||
// each shaper is responsible to call ReleaseGrFace on its entry when
|
||||
// finished with it, so that we know when it can be deleted.
|
||||
gr_face* mGrFace;
|
||||
|
||||
// hashtable to map raw table data ptr back to its owning blob, for use by
|
||||
// graphite table-release callback
|
||||
nsDataHashtable<nsPtrHashKey<const void>,void*>* mGrTableMap;
|
||||
|
||||
// number of current users of this entry's mGrFace
|
||||
nsrefcnt mGrFaceRefCnt;
|
||||
|
||||
static const void* GrGetTable(const void *aAppFaceHandle,
|
||||
unsigned int aName,
|
||||
size_t *aLen);
|
||||
static void GrReleaseTable(const void *aAppFaceHandle,
|
||||
const void *aTableBuffer);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Font table hashtable, to support GetFontTable for harfbuzz.
|
||||
*
|
||||
* The harfbuzz shaper (and potentially other clients) needs access to raw
|
||||
* font table data. This needs to be cached so that it can be used
|
||||
* repeatedly (each time we construct a text run; in some cases, for
|
||||
* each character/glyph within the run) without re-fetching large tables
|
||||
* every time.
|
||||
*
|
||||
* Because we may instantiate many gfxFonts for the same physical font
|
||||
* file (at different sizes), we should ensure that they can share a
|
||||
* single cached copy of the font tables. To do this, we implement table
|
||||
* access and sharing on the fontEntry rather than the font itself.
|
||||
*
|
||||
* The default implementation uses GetFontTable() to read font table
|
||||
* data into byte arrays, and wraps them in blobs which are registered in
|
||||
* a hashtable. The hashtable can then return pre-existing blobs to
|
||||
* harfbuzz.
|
||||
*
|
||||
* Harfbuzz will "destroy" the blobs when it is finished with them. When
|
||||
* the last blob reference is removed, the FontTableBlobData user data
|
||||
* will remove the blob from the hashtable if still registered.
|
||||
*/
|
||||
|
||||
class FontTableBlobData;
|
||||
|
||||
/**
|
||||
* FontTableHashEntry manages the entries of hb_blob_t's containing font
|
||||
* table data.
|
||||
*
|
||||
* This is used to share font tables across fonts with the same
|
||||
* font entry (but different sizes) for use by HarfBuzz. The hashtable
|
||||
* does not own a strong reference to the blob, but keeps a weak pointer,
|
||||
* managed by FontTableBlobData. Similarly FontTableBlobData keeps only a
|
||||
* weak pointer to the hashtable, managed by FontTableHashEntry.
|
||||
*/
|
||||
|
||||
class FontTableHashEntry : public nsUint32HashKey
|
||||
{
|
||||
public:
|
||||
// Declarations for nsTHashtable
|
||||
|
||||
typedef nsUint32HashKey KeyClass;
|
||||
typedef KeyClass::KeyType KeyType;
|
||||
typedef KeyClass::KeyTypePointer KeyTypePointer;
|
||||
|
||||
explicit FontTableHashEntry(KeyTypePointer aTag)
|
||||
: KeyClass(aTag)
|
||||
, mSharedBlobData(nullptr)
|
||||
, mBlob(nullptr)
|
||||
{ }
|
||||
|
||||
// NOTE: This assumes the new entry belongs to the same hashtable as
|
||||
// the old, because the mHashtable pointer in mSharedBlobData (if
|
||||
// present) will not be updated.
|
||||
FontTableHashEntry(FontTableHashEntry&& toMove)
|
||||
: KeyClass(mozilla::Move(toMove))
|
||||
, mSharedBlobData(mozilla::Move(toMove.mSharedBlobData))
|
||||
, mBlob(mozilla::Move(toMove.mBlob))
|
||||
{
|
||||
toMove.mSharedBlobData = nullptr;
|
||||
toMove.mBlob = nullptr;
|
||||
}
|
||||
|
||||
~FontTableHashEntry() { Clear(); }
|
||||
|
||||
// FontTable/Blob API
|
||||
|
||||
// Transfer (not copy) elements of aTable to a new hb_blob_t and
|
||||
// return ownership to the caller. A weak reference to the blob is
|
||||
// recorded in the hashtable entry so that others may use the same
|
||||
// table.
|
||||
hb_blob_t *
|
||||
ShareTableAndGetBlob(FallibleTArray<uint8_t>& aTable,
|
||||
nsTHashtable<FontTableHashEntry> *aHashtable);
|
||||
|
||||
// Return a strong reference to the blob.
|
||||
// Callers must hb_blob_destroy the returned blob.
|
||||
hb_blob_t *GetBlob() const;
|
||||
|
||||
void Clear();
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
private:
|
||||
static void DeleteFontTableBlobData(void *aBlobData);
|
||||
// not implemented
|
||||
FontTableHashEntry& operator=(FontTableHashEntry& toCopy);
|
||||
|
||||
FontTableBlobData *mSharedBlobData;
|
||||
hb_blob_t *mBlob;
|
||||
};
|
||||
|
||||
nsAutoPtr<nsTHashtable<FontTableHashEntry> > mFontTableCache;
|
||||
|
||||
gfxFontEntry(const gfxFontEntry&);
|
||||
gfxFontEntry& operator=(const gfxFontEntry&);
|
||||
};
|
||||
|
||||
|
||||
// used when iterating over all fonts looking for a match for a given character
|
||||
struct GlobalFontMatch {
|
||||
GlobalFontMatch(const uint32_t aCharacter,
|
||||
int32_t aRunScript,
|
||||
const gfxFontStyle *aStyle) :
|
||||
mCh(aCharacter), mRunScript(aRunScript), mStyle(aStyle),
|
||||
mMatchRank(0), mCount(0), mCmapsTested(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const uint32_t mCh; // codepoint to be matched
|
||||
int32_t mRunScript; // Unicode script for the codepoint
|
||||
const gfxFontStyle* mStyle; // style to match
|
||||
int32_t mMatchRank; // metric indicating closest match
|
||||
nsRefPtr<gfxFontEntry> mBestMatch; // current best match
|
||||
nsRefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
|
||||
uint32_t mCount; // number of fonts matched
|
||||
uint32_t mCmapsTested; // number of cmaps tested
|
||||
};
|
||||
|
||||
class gfxFontFamily {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(gfxFontFamily)
|
||||
|
||||
explicit gfxFontFamily(const nsAString& aName) :
|
||||
mName(aName),
|
||||
mOtherFamilyNamesInitialized(false),
|
||||
mHasOtherFamilyNames(false),
|
||||
mFaceNamesInitialized(false),
|
||||
mHasStyles(false),
|
||||
mIsSimpleFamily(false),
|
||||
mIsBadUnderlineFamily(false),
|
||||
mFamilyCharacterMapInitialized(false),
|
||||
mSkipDefaultFeatureSpaceCheck(false)
|
||||
{ }
|
||||
|
||||
const nsString& Name() { return mName; }
|
||||
|
||||
virtual void LocalizedName(nsAString& aLocalizedName);
|
||||
virtual bool HasOtherFamilyNames();
|
||||
|
||||
nsTArray<nsRefPtr<gfxFontEntry> >& GetFontList() { return mAvailableFonts; }
|
||||
|
||||
void AddFontEntry(nsRefPtr<gfxFontEntry> aFontEntry) {
|
||||
// bug 589682 - set the IgnoreGDEF flag on entries for Italic faces
|
||||
// of Times New Roman, because of buggy table in those fonts
|
||||
if (aFontEntry->IsItalic() && !aFontEntry->IsUserFont() &&
|
||||
Name().EqualsLiteral("Times New Roman"))
|
||||
{
|
||||
aFontEntry->mIgnoreGDEF = true;
|
||||
}
|
||||
if (aFontEntry->mFamilyName.IsEmpty()) {
|
||||
aFontEntry->mFamilyName = Name();
|
||||
} else {
|
||||
MOZ_ASSERT(aFontEntry->mFamilyName.Equals(Name()));
|
||||
}
|
||||
aFontEntry->mSkipDefaultFeatureSpaceCheck = mSkipDefaultFeatureSpaceCheck;
|
||||
mAvailableFonts.AppendElement(aFontEntry);
|
||||
}
|
||||
|
||||
// note that the styles for this family have been added
|
||||
bool HasStyles() { return mHasStyles; }
|
||||
void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; }
|
||||
|
||||
// choose a specific face to match a style using CSS font matching
|
||||
// rules (weight matching occurs here). may return a face that doesn't
|
||||
// precisely match (e.g. normal face when no italic face exists).
|
||||
// aNeedsSyntheticBold is set to true when synthetic bolding is
|
||||
// needed, false otherwise
|
||||
gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle,
|
||||
bool& aNeedsSyntheticBold);
|
||||
|
||||
// checks for a matching font within the family
|
||||
// used as part of the font fallback process
|
||||
void FindFontForChar(GlobalFontMatch *aMatchData);
|
||||
|
||||
// checks all fonts for a matching font within the family
|
||||
void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
|
||||
|
||||
// read in other family names, if any, and use functor to add each into cache
|
||||
virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
|
||||
|
||||
// helper method for reading localized family names from the name table
|
||||
// of a single face
|
||||
static void ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
|
||||
const char *aNameData,
|
||||
uint32_t aDataLength,
|
||||
nsTArray<nsString>& aOtherFamilyNames,
|
||||
bool useFullName);
|
||||
|
||||
// set when other family names have been read in
|
||||
void SetOtherFamilyNamesInitialized() {
|
||||
mOtherFamilyNamesInitialized = true;
|
||||
}
|
||||
|
||||
// read in other localized family names, fullnames and Postscript names
|
||||
// for all faces and append to lookup tables
|
||||
virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
|
||||
bool aNeedFullnamePostscriptNames,
|
||||
FontInfoData *aFontInfoData = nullptr);
|
||||
|
||||
// find faces belonging to this family (platform implementations override this;
|
||||
// should be made pure virtual once all subclasses have been updated)
|
||||
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) { }
|
||||
|
||||
// search for a specific face using the Postscript name
|
||||
gfxFontEntry* FindFont(const nsAString& aPostscriptName);
|
||||
|
||||
// read in cmaps for all the faces
|
||||
void ReadAllCMAPs(FontInfoData *aFontInfoData = nullptr);
|
||||
|
||||
bool TestCharacterMap(uint32_t aCh) {
|
||||
if (!mFamilyCharacterMapInitialized) {
|
||||
ReadAllCMAPs();
|
||||
}
|
||||
return mFamilyCharacterMap.test(aCh);
|
||||
}
|
||||
|
||||
void ResetCharacterMap() {
|
||||
mFamilyCharacterMap.reset();
|
||||
mFamilyCharacterMapInitialized = false;
|
||||
}
|
||||
|
||||
// mark this family as being in the "bad" underline offset blacklist
|
||||
void SetBadUnderlineFamily() {
|
||||
mIsBadUnderlineFamily = true;
|
||||
if (mHasStyles) {
|
||||
SetBadUnderlineFonts();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; }
|
||||
|
||||
// sort available fonts to put preferred (standard) faces towards the end
|
||||
void SortAvailableFonts();
|
||||
|
||||
// check whether the family fits into the simple 4-face model,
|
||||
// so we can use simplified style-matching;
|
||||
// if so set the mIsSimpleFamily flag (defaults to False before we've checked)
|
||||
void CheckForSimpleFamily();
|
||||
|
||||
// For memory reporter
|
||||
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Only used for debugging checks - does a linear search
|
||||
bool ContainsFace(gfxFontEntry* aFontEntry);
|
||||
#endif
|
||||
|
||||
void SetSkipSpaceFeatureCheck(bool aSkipCheck) {
|
||||
mSkipDefaultFeatureSpaceCheck = aSkipCheck;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
virtual ~gfxFontFamily()
|
||||
{
|
||||
}
|
||||
|
||||
// fills in an array with weights of faces that match style,
|
||||
// returns whether any matching entries found
|
||||
virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
|
||||
bool anItalic, int16_t aStretch);
|
||||
|
||||
bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
|
||||
hb_blob_t *aNameTable,
|
||||
bool useFullName = false);
|
||||
|
||||
// set whether this font family is in "bad" underline offset blacklist.
|
||||
void SetBadUnderlineFonts() {
|
||||
uint32_t i, numFonts = mAvailableFonts.Length();
|
||||
for (i = 0; i < numFonts; i++) {
|
||||
if (mAvailableFonts[i]) {
|
||||
mAvailableFonts[i]->mIsBadUnderlineFont = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsString mName;
|
||||
nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
|
||||
gfxSparseBitSet mFamilyCharacterMap;
|
||||
bool mOtherFamilyNamesInitialized : 1;
|
||||
bool mHasOtherFamilyNames : 1;
|
||||
bool mFaceNamesInitialized : 1;
|
||||
bool mHasStyles : 1;
|
||||
bool mIsSimpleFamily : 1;
|
||||
bool mIsBadUnderlineFamily : 1;
|
||||
bool mFamilyCharacterMapInitialized : 1;
|
||||
bool mSkipDefaultFeatureSpaceCheck : 1;
|
||||
|
||||
enum {
|
||||
// for "simple" families, the faces are stored in mAvailableFonts
|
||||
// with fixed positions:
|
||||
kRegularFaceIndex = 0,
|
||||
kBoldFaceIndex = 1,
|
||||
kItalicFaceIndex = 2,
|
||||
kBoldItalicFaceIndex = 3,
|
||||
// mask values for selecting face with bold and/or italic attributes
|
||||
kBoldMask = 0x01,
|
||||
kItalicMask = 0x02
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "gfxTextRun.h"
|
||||
|
||||
#include "cairo-win32.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "gfxGlyphExtents.h"
|
||||
#include "gfxTextRun.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef DEBUG_roc
|
||||
#define DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
extern uint32_t gTextRunStorageHighWaterMark;
|
||||
extern uint32_t gTextRunStorage;
|
||||
extern uint32_t gFontCount;
|
||||
extern uint32_t gGlyphExtentsCount;
|
||||
extern uint32_t gGlyphExtentsWidthsTotalSize;
|
||||
extern uint32_t gGlyphExtentsSetupEagerSimple;
|
||||
extern uint32_t gGlyphExtentsSetupEagerTight;
|
||||
extern uint32_t gGlyphExtentsSetupLazyTight;
|
||||
extern uint32_t gGlyphExtentsSetupFallBackToTight;
|
||||
#endif
|
||||
|
||||
gfxGlyphExtents::~gfxGlyphExtents()
|
||||
{
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
gGlyphExtentsWidthsTotalSize +=
|
||||
mContainedGlyphWidths.SizeOfExcludingThis(&FontCacheMallocSizeOf);
|
||||
gGlyphExtentsCount++;
|
||||
#endif
|
||||
MOZ_COUNT_DTOR(gfxGlyphExtents);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
|
||||
gfxContext *aContext, uint32_t aGlyphID, gfxRect *aExtents)
|
||||
{
|
||||
HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
|
||||
if (!entry) {
|
||||
if (!aContext) {
|
||||
NS_WARNING("Could not get glyph extents (no aContext)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aFont->SetupCairoFont(aContext)) {
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
++gGlyphExtentsSetupLazyTight;
|
||||
#endif
|
||||
aFont->SetupGlyphExtents(aContext, aGlyphID, true, this);
|
||||
entry = mTightGlyphExtents.GetEntry(aGlyphID);
|
||||
}
|
||||
if (!entry) {
|
||||
NS_WARNING("Could not get glyph extents");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*aExtents = gfxRect(entry->x, entry->y, entry->width, entry->height);
|
||||
return true;
|
||||
}
|
||||
|
||||
gfxGlyphExtents::GlyphWidths::~GlyphWidths()
|
||||
{
|
||||
uint32_t i, count = mBlocks.Length();
|
||||
for (i = 0; i < count; ++i) {
|
||||
uintptr_t bits = mBlocks[i];
|
||||
if (bits && !(bits & 0x1)) {
|
||||
delete[] reinterpret_cast<uint16_t *>(bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
gfxGlyphExtents::GlyphWidths::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t size = mBlocks.SizeOfExcludingThis(aMallocSizeOf);
|
||||
for (i = 0; i < mBlocks.Length(); ++i) {
|
||||
uintptr_t bits = mBlocks[i];
|
||||
if (bits && !(bits & 0x1)) {
|
||||
size += aMallocSizeOf(reinterpret_cast<void*>(bits));
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
gfxGlyphExtents::GlyphWidths::Set(uint32_t aGlyphID, uint16_t aWidth)
|
||||
{
|
||||
uint32_t block = aGlyphID >> BLOCK_SIZE_BITS;
|
||||
uint32_t len = mBlocks.Length();
|
||||
if (block >= len) {
|
||||
uintptr_t *elems = mBlocks.AppendElements(block + 1 - len);
|
||||
if (!elems)
|
||||
return;
|
||||
memset(elems, 0, sizeof(uintptr_t)*(block + 1 - len));
|
||||
}
|
||||
|
||||
uintptr_t bits = mBlocks[block];
|
||||
uint32_t glyphOffset = aGlyphID & (BLOCK_SIZE - 1);
|
||||
if (!bits) {
|
||||
mBlocks[block] = MakeSingle(glyphOffset, aWidth);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t *newBlock;
|
||||
if (bits & 0x1) {
|
||||
// Expand the block to a real block. We could avoid this by checking
|
||||
// glyphOffset == GetGlyphOffset(bits), but that never happens so don't bother
|
||||
newBlock = new uint16_t[BLOCK_SIZE];
|
||||
if (!newBlock)
|
||||
return;
|
||||
uint32_t i;
|
||||
for (i = 0; i < BLOCK_SIZE; ++i) {
|
||||
newBlock[i] = INVALID_WIDTH;
|
||||
}
|
||||
newBlock[GetGlyphOffset(bits)] = GetWidth(bits);
|
||||
mBlocks[block] = reinterpret_cast<uintptr_t>(newBlock);
|
||||
} else {
|
||||
newBlock = reinterpret_cast<uint16_t *>(bits);
|
||||
}
|
||||
newBlock[glyphOffset] = aWidth;
|
||||
}
|
||||
|
||||
void
|
||||
gfxGlyphExtents::SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits)
|
||||
{
|
||||
HashEntry *entry = mTightGlyphExtents.PutEntry(aGlyphID);
|
||||
if (!entry)
|
||||
return;
|
||||
entry->x = aExtentsAppUnits.X();
|
||||
entry->y = aExtentsAppUnits.Y();
|
||||
entry->width = aExtentsAppUnits.Width();
|
||||
entry->height = aExtentsAppUnits.Height();
|
||||
}
|
||||
|
||||
size_t
|
||||
gfxGlyphExtents::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return mContainedGlyphWidths.SizeOfExcludingThis(aMallocSizeOf) +
|
||||
mTightGlyphExtents.SizeOfExcludingThis(nullptr, aMallocSizeOf);
|
||||
}
|
||||
|
||||
size_t
|
||||
gfxGlyphExtents::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef GFX_GLYPHEXTENTS_H
|
||||
#define GFX_GLYPHEXTENTS_H
|
||||
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
class gfxContext;
|
||||
class gfxFont;
|
||||
struct gfxRect;
|
||||
|
||||
/**
|
||||
* This stores glyph bounds information for a particular gfxFont, at
|
||||
* a particular appunits-per-dev-pixel ratio (because the compressed glyph
|
||||
* width array is stored in appunits).
|
||||
*
|
||||
* We store a hashtable from glyph IDs to float bounding rects. For the
|
||||
* common case where the glyph has no horizontal left bearing, and no
|
||||
* y overflow above the font ascent or below the font descent, and tight
|
||||
* bounding boxes are not required, we avoid storing the glyph ID in the hashtable
|
||||
* and instead consult an array of 16-bit glyph XMost values (in appunits).
|
||||
* This array always has an entry for the font's space glyph --- the width is
|
||||
* assumed to be zero.
|
||||
*/
|
||||
class gfxGlyphExtents {
|
||||
public:
|
||||
explicit gfxGlyphExtents(int32_t aAppUnitsPerDevUnit) :
|
||||
mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {
|
||||
MOZ_COUNT_CTOR(gfxGlyphExtents);
|
||||
}
|
||||
~gfxGlyphExtents();
|
||||
|
||||
enum { INVALID_WIDTH = 0xFFFF };
|
||||
|
||||
void NotifyGlyphsChanged() {
|
||||
mTightGlyphExtents.Clear();
|
||||
}
|
||||
|
||||
// returns INVALID_WIDTH => not a contained glyph
|
||||
// Otherwise the glyph has no before-bearing or vertical bearings,
|
||||
// and the result is its width measured from the baseline origin, in
|
||||
// appunits.
|
||||
uint16_t GetContainedGlyphWidthAppUnits(uint32_t aGlyphID) const {
|
||||
return mContainedGlyphWidths.Get(aGlyphID);
|
||||
}
|
||||
|
||||
bool IsGlyphKnown(uint32_t aGlyphID) const {
|
||||
return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
|
||||
mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
|
||||
}
|
||||
|
||||
bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID) const {
|
||||
return mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
|
||||
}
|
||||
|
||||
// Get glyph extents; a rectangle relative to the left baseline origin
|
||||
// Returns true on success. Can fail on OOM or when aContext is null
|
||||
// and extents were not (successfully) prefetched.
|
||||
bool GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext,
|
||||
uint32_t aGlyphID, gfxRect *aExtents);
|
||||
|
||||
void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) {
|
||||
mContainedGlyphWidths.Set(aGlyphID, aWidth);
|
||||
}
|
||||
void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits);
|
||||
|
||||
int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
private:
|
||||
class HashEntry : public nsUint32HashKey {
|
||||
public:
|
||||
// When constructing a new entry in the hashtable, we'll leave this
|
||||
// blank. The caller of Put() will fill this in.
|
||||
explicit HashEntry(KeyTypePointer aPtr) : nsUint32HashKey(aPtr) {}
|
||||
HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) {
|
||||
x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.height;
|
||||
}
|
||||
|
||||
float x, y, width, height;
|
||||
};
|
||||
|
||||
enum { BLOCK_SIZE_BITS = 7, BLOCK_SIZE = 1 << BLOCK_SIZE_BITS }; // 128-glyph blocks
|
||||
|
||||
class GlyphWidths {
|
||||
public:
|
||||
void Set(uint32_t aIndex, uint16_t aValue);
|
||||
uint16_t Get(uint32_t aIndex) const {
|
||||
uint32_t block = aIndex >> BLOCK_SIZE_BITS;
|
||||
if (block >= mBlocks.Length())
|
||||
return INVALID_WIDTH;
|
||||
uintptr_t bits = mBlocks[block];
|
||||
if (!bits)
|
||||
return INVALID_WIDTH;
|
||||
uint32_t indexInBlock = aIndex & (BLOCK_SIZE - 1);
|
||||
if (bits & 0x1) {
|
||||
if (GetGlyphOffset(bits) != indexInBlock)
|
||||
return INVALID_WIDTH;
|
||||
return GetWidth(bits);
|
||||
}
|
||||
uint16_t *widths = reinterpret_cast<uint16_t *>(bits);
|
||||
return widths[indexInBlock];
|
||||
}
|
||||
|
||||
uint32_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
~GlyphWidths();
|
||||
|
||||
private:
|
||||
static uint32_t GetGlyphOffset(uintptr_t aBits) {
|
||||
NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
|
||||
return (aBits >> 1) & ((1 << BLOCK_SIZE_BITS) - 1);
|
||||
}
|
||||
static uint32_t GetWidth(uintptr_t aBits) {
|
||||
NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
|
||||
return aBits >> (1 + BLOCK_SIZE_BITS);
|
||||
}
|
||||
static uintptr_t MakeSingle(uint32_t aGlyphOffset, uint16_t aWidth) {
|
||||
return (aWidth << (1 + BLOCK_SIZE_BITS)) + (aGlyphOffset << 1) + 1;
|
||||
}
|
||||
|
||||
nsTArray<uintptr_t> mBlocks;
|
||||
};
|
||||
|
||||
GlyphWidths mContainedGlyphWidths;
|
||||
nsTHashtable<HashEntry> mTightGlyphExtents;
|
||||
int32_t mAppUnitsPerDevUnit;
|
||||
|
||||
private:
|
||||
// not implemented:
|
||||
gfxGlyphExtents(const gfxGlyphExtents& aOther) MOZ_DELETE;
|
||||
gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) MOZ_DELETE;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
#include "nsString.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "gfxTextRun.h"
|
||||
|
||||
#include "graphite2/Font.h"
|
||||
#include "graphite2/Segment.h"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "gfxFontConstants.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#include "gfxFontUtils.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "nsUnicodeScriptCodes.h"
|
||||
#include "nsUnicodeNormalizer.h"
|
||||
|
@ -1009,7 +1010,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
|||
hb_buffer_set_direction(buffer, isRightToLeft ? HB_DIRECTION_RTL :
|
||||
HB_DIRECTION_LTR);
|
||||
hb_script_t scriptTag;
|
||||
if (aShapedText->Flags() & gfxTextRunFactory::TEXT_USE_MATH_SCRIPT) {
|
||||
if (aShapedText->GetFlags() & gfxTextRunFactory::TEXT_USE_MATH_SCRIPT) {
|
||||
scriptTag = sMathScript;
|
||||
} else {
|
||||
scriptTag = GetHBScriptUsedForShaping(aScript);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "gfxFontUtils.h"
|
||||
#include "gfxMacPlatformFontList.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "gfxTextRun.h"
|
||||
|
||||
#include "cairo-quartz.h"
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "cairo.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxTextRun.h"
|
||||
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsTArray.h"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "gfxTextRun.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <process.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "prlog.h"
|
||||
|
||||
#include "gfxPlatformFontList.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
|
||||
#include "nsUnicharUtils.h"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "gfxMacPlatformFontList.h"
|
||||
#include "gfxMacFont.h"
|
||||
#include "gfxCoreTextShaper.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,996 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef GFX_TEXTRUN_H
|
||||
#define GFX_TEXTRUN_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
#include "nsString.h"
|
||||
#include "gfxPoint.h"
|
||||
#include "gfxFont.h"
|
||||
#include "nsTArray.h"
|
||||
#include "gfxSkipChars.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "DrawMode.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
class gfxContext;
|
||||
class gfxFontGroup;
|
||||
class gfxUserFontSet;
|
||||
class gfxTextContextPaint;
|
||||
class nsIAtom;
|
||||
class nsILanguageAtomService;
|
||||
|
||||
/**
|
||||
* Callback for Draw() to use when drawing text with mode
|
||||
* DrawMode::GLYPH_PATH.
|
||||
*/
|
||||
struct gfxTextRunDrawCallbacks {
|
||||
|
||||
/**
|
||||
* Constructs a new DrawCallbacks object.
|
||||
*
|
||||
* @param aShouldPaintSVGGlyphs If true, SVG glyphs will be
|
||||
* painted and the NotifyBeforeSVGGlyphPainted/NotifyAfterSVGGlyphPainted
|
||||
* callbacks will be invoked for each SVG glyph. If false, SVG glyphs
|
||||
* will not be painted; fallback plain glyphs are not emitted either.
|
||||
*/
|
||||
explicit gfxTextRunDrawCallbacks(bool aShouldPaintSVGGlyphs = false)
|
||||
: mShouldPaintSVGGlyphs(aShouldPaintSVGGlyphs)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a path has been emitted to the gfxContext when
|
||||
* painting a text run. This can be called any number of times,
|
||||
* due to partial ligatures and intervening SVG glyphs.
|
||||
*/
|
||||
virtual void NotifyGlyphPathEmitted() = 0;
|
||||
|
||||
/**
|
||||
* Called just before an SVG glyph has been painted to the gfxContext.
|
||||
*/
|
||||
virtual void NotifyBeforeSVGGlyphPainted() { }
|
||||
|
||||
/**
|
||||
* Called just after an SVG glyph has been painted to the gfxContext.
|
||||
*/
|
||||
virtual void NotifyAfterSVGGlyphPainted() { }
|
||||
|
||||
bool mShouldPaintSVGGlyphs;
|
||||
};
|
||||
|
||||
/**
|
||||
* gfxTextRun is an abstraction for drawing and measuring substrings of a run
|
||||
* of text. It stores runs of positioned glyph data, each run having a single
|
||||
* gfxFont. The glyphs are associated with a string of source text, and the
|
||||
* gfxTextRun APIs take parameters that are offsets into that source text.
|
||||
*
|
||||
* gfxTextRuns are not refcounted. They should be deleted when no longer required.
|
||||
*
|
||||
* gfxTextRuns are mostly immutable. The only things that can change are
|
||||
* inter-cluster spacing and line break placement. Spacing is always obtained
|
||||
* lazily by methods that need it, it is not cached. Line breaks are stored
|
||||
* persistently (insofar as they affect the shaping of glyphs; gfxTextRun does
|
||||
* not actually do anything to explicitly account for line breaks). Initially
|
||||
* there are no line breaks. The textrun can record line breaks before or after
|
||||
* any given cluster. (Line breaks specified inside clusters are ignored.)
|
||||
*
|
||||
* It is important that zero-length substrings are handled correctly. This will
|
||||
* be on the test!
|
||||
*/
|
||||
class gfxTextRun : public gfxShapedText {
|
||||
public:
|
||||
|
||||
// Override operator delete to properly free the object that was
|
||||
// allocated via moz_malloc.
|
||||
void operator delete(void* p) {
|
||||
moz_free(p);
|
||||
}
|
||||
|
||||
virtual ~gfxTextRun();
|
||||
|
||||
typedef gfxFont::RunMetrics Metrics;
|
||||
|
||||
// Public textrun API for general use
|
||||
|
||||
bool IsClusterStart(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsClusterStart();
|
||||
}
|
||||
bool IsLigatureGroupStart(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].IsLigatureGroupStart();
|
||||
}
|
||||
bool CanBreakLineBefore(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CanBreakBefore() ==
|
||||
CompressedGlyph::FLAG_BREAK_TYPE_NORMAL;
|
||||
}
|
||||
bool CanHyphenateBefore(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CanBreakBefore() ==
|
||||
CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
|
||||
}
|
||||
|
||||
bool CharIsSpace(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsSpace();
|
||||
}
|
||||
bool CharIsTab(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsTab();
|
||||
}
|
||||
bool CharIsNewline(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsNewline();
|
||||
}
|
||||
bool CharIsLowSurrogate(uint32_t aPos) {
|
||||
NS_ASSERTION(aPos < GetLength(), "aPos out of range");
|
||||
return mCharacterGlyphs[aPos].CharIsLowSurrogate();
|
||||
}
|
||||
|
||||
// All uint32_t aStart, uint32_t aLength ranges below are restricted to
|
||||
// grapheme cluster boundaries! All offsets are in terms of the string
|
||||
// passed into MakeTextRun.
|
||||
|
||||
// All coordinates are in layout/app units
|
||||
|
||||
/**
|
||||
* Set the potential linebreaks for a substring of the textrun. These are
|
||||
* the "allow break before" points. Initially, there are no potential
|
||||
* linebreaks.
|
||||
*
|
||||
* This can change glyphs and/or geometry! Some textruns' shapes
|
||||
* depend on potential line breaks (e.g., title-case-converting textruns).
|
||||
* This function is virtual so that those textruns can reshape themselves.
|
||||
*
|
||||
* @return true if this changed the linebreaks, false if the new line
|
||||
* breaks are the same as the old
|
||||
*/
|
||||
virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
|
||||
uint8_t *aBreakBefore,
|
||||
gfxContext *aRefContext);
|
||||
|
||||
/**
|
||||
* Layout provides PropertyProvider objects. These allow detection of
|
||||
* potential line break points and computation of spacing. We pass the data
|
||||
* this way to allow lazy data acquisition; for example BreakAndMeasureText
|
||||
* will want to only ask for properties of text it's actually looking at.
|
||||
*
|
||||
* NOTE that requested spacing may not actually be applied, if the textrun
|
||||
* is unable to apply it in some context. Exception: spacing around a
|
||||
* whitespace character MUST always be applied.
|
||||
*/
|
||||
class PropertyProvider {
|
||||
public:
|
||||
// Detect hyphenation break opportunities in the given range; breaks
|
||||
// not at cluster boundaries will be ignored.
|
||||
virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
|
||||
bool *aBreakBefore) = 0;
|
||||
|
||||
// Returns the provider's hyphenation setting, so callers can decide
|
||||
// whether it is necessary to call GetHyphenationBreaks.
|
||||
// Result is an NS_STYLE_HYPHENS_* value.
|
||||
virtual int8_t GetHyphensOption() = 0;
|
||||
|
||||
// Returns the extra width that will be consumed by a hyphen. This should
|
||||
// be constant for a given textrun.
|
||||
virtual gfxFloat GetHyphenWidth() = 0;
|
||||
|
||||
typedef gfxFont::Spacing Spacing;
|
||||
|
||||
/**
|
||||
* Get the spacing around the indicated characters. Spacing must be zero
|
||||
* inside clusters. In other words, if character i is not
|
||||
* CLUSTER_START, then character i-1 must have zero after-spacing and
|
||||
* character i must have zero before-spacing.
|
||||
*/
|
||||
virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
|
||||
Spacing *aSpacing) = 0;
|
||||
|
||||
// Returns a gfxContext that can be used to measure the hyphen glyph.
|
||||
// Only called if the hyphen width is requested.
|
||||
virtual already_AddRefed<gfxContext> GetContext() = 0;
|
||||
|
||||
// Return the appUnitsPerDevUnit value to be used when measuring.
|
||||
// Only called if the hyphen width is requested.
|
||||
virtual uint32_t GetAppUnitsPerDevUnit() = 0;
|
||||
};
|
||||
|
||||
class ClusterIterator {
|
||||
public:
|
||||
explicit ClusterIterator(gfxTextRun *aTextRun);
|
||||
|
||||
void Reset();
|
||||
|
||||
bool NextCluster();
|
||||
|
||||
uint32_t Position() const {
|
||||
return mCurrentChar;
|
||||
}
|
||||
|
||||
uint32_t ClusterLength() const;
|
||||
|
||||
gfxFloat ClusterAdvance(PropertyProvider *aProvider) const;
|
||||
|
||||
private:
|
||||
gfxTextRun *mTextRun;
|
||||
uint32_t mCurrentChar;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a substring. Uses only GetSpacing from aBreakProvider.
|
||||
* The provided point is the baseline origin on the left of the string
|
||||
* for LTR, on the right of the string for RTL.
|
||||
* @param aAdvanceWidth if non-null, the advance width of the substring
|
||||
* is returned here.
|
||||
*
|
||||
* Drawing should respect advance widths in the sense that for LTR runs,
|
||||
* Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by
|
||||
* Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2,
|
||||
* dirty, &provider, nullptr) should have the same effect as
|
||||
* Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
|
||||
* For RTL runs the rule is:
|
||||
* Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by
|
||||
* Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1,
|
||||
* dirty, &provider, nullptr) should have the same effect as
|
||||
* Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr).
|
||||
*
|
||||
* Glyphs should be drawn in logical content order, which can be significant
|
||||
* if they overlap (perhaps due to negative spacing).
|
||||
*/
|
||||
void Draw(gfxContext *aContext, gfxPoint aPt,
|
||||
DrawMode aDrawMode,
|
||||
uint32_t aStart, uint32_t aLength,
|
||||
PropertyProvider *aProvider,
|
||||
gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint,
|
||||
gfxTextRunDrawCallbacks *aCallbacks = nullptr);
|
||||
|
||||
/**
|
||||
* Computes the ReflowMetrics for a substring.
|
||||
* Uses GetSpacing from aBreakProvider.
|
||||
* @param aBoundingBoxType which kind of bounding box (loose/tight)
|
||||
*/
|
||||
Metrics MeasureText(uint32_t aStart, uint32_t aLength,
|
||||
gfxFont::BoundingBoxType aBoundingBoxType,
|
||||
gfxContext *aRefContextForTightBoundingBox,
|
||||
PropertyProvider *aProvider);
|
||||
|
||||
/**
|
||||
* Computes just the advance width for a substring.
|
||||
* Uses GetSpacing from aBreakProvider.
|
||||
*/
|
||||
gfxFloat GetAdvanceWidth(uint32_t aStart, uint32_t aLength,
|
||||
PropertyProvider *aProvider);
|
||||
|
||||
/**
|
||||
* Clear all stored line breaks for the given range (both before and after),
|
||||
* and then set the line-break state before aStart to aBreakBefore and
|
||||
* after the last cluster to aBreakAfter.
|
||||
*
|
||||
* We require that before and after line breaks be consistent. For clusters
|
||||
* i and i+1, we require that if there is a break after cluster i, a break
|
||||
* will be specified before cluster i+1. This may be temporarily violated
|
||||
* (e.g. after reflowing line L and before reflowing line L+1); to handle
|
||||
* these temporary violations, we say that there is a break betwen i and i+1
|
||||
* if a break is specified after i OR a break is specified before i+1.
|
||||
*
|
||||
* This can change textrun geometry! The existence of a linebreak can affect
|
||||
* the advance width of the cluster before the break (when kerning) or the
|
||||
* geometry of one cluster before the break or any number of clusters
|
||||
* after the break. (The one-cluster-before-the-break limit is somewhat
|
||||
* arbitrary; if some scripts require breaking it, then we need to
|
||||
* alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
|
||||
* it could affect the layout of frames before it...)
|
||||
*
|
||||
* We return true if glyphs or geometry changed, false otherwise. This
|
||||
* function is virtual so that gfxTextRun subclasses can reshape
|
||||
* properly.
|
||||
*
|
||||
* @param aAdvanceWidthDelta if non-null, returns the change in advance
|
||||
* width of the given range.
|
||||
*/
|
||||
virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength,
|
||||
bool aLineBreakBefore, bool aLineBreakAfter,
|
||||
gfxFloat *aAdvanceWidthDelta,
|
||||
gfxContext *aRefContext);
|
||||
|
||||
/**
|
||||
* Finds the longest substring that will fit into the given width.
|
||||
* Uses GetHyphenationBreaks and GetSpacing from aBreakProvider.
|
||||
* Guarantees the following:
|
||||
* -- 0 <= result <= aMaxLength
|
||||
* -- result is the maximal value of N such that either
|
||||
* N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
|
||||
* OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
|
||||
* OR N == aMaxLength && GetAdvanceWidth(aStart, N) <= aWidth
|
||||
* where GetAdvanceWidth assumes the effect of
|
||||
* SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
|
||||
* -- if no such N exists, then result is the smallest N such that
|
||||
* N < aMaxLength && line break at N
|
||||
* OR N < aMaxLength && hyphen break at N
|
||||
* OR N == aMaxLength
|
||||
*
|
||||
* The call has the effect of
|
||||
* SetLineBreaks(aStart, result, aLineBreakBefore, result < aMaxLength, aProvider)
|
||||
* and the returned metrics and the invariants above reflect this.
|
||||
*
|
||||
* @param aMaxLength this can be UINT32_MAX, in which case the length used
|
||||
* is up to the end of the string
|
||||
* @param aLineBreakBefore set to true if and only if there is an actual
|
||||
* line break at the start of this string.
|
||||
* @param aSuppressInitialBreak if true, then we assume there is no possible
|
||||
* linebreak before aStart. If false, then we will check the internal
|
||||
* line break opportunity state before deciding whether to return 0 as the
|
||||
* character to break before.
|
||||
* @param aTrimWhitespace if non-null, then we allow a trailing run of
|
||||
* spaces to be trimmed; the width of the space(s) will not be included in
|
||||
* the measured string width for comparison with the limit aWidth, and
|
||||
* trimmed spaces will not be included in returned metrics. The width
|
||||
* of the trimmed spaces will be returned in aTrimWhitespace.
|
||||
* Trimmed spaces are still counted in the "characters fit" result.
|
||||
* @param aMetrics if non-null, we fill this in for the returned substring.
|
||||
* If a hyphenation break was used, the hyphen is NOT included in the returned metrics.
|
||||
* @param aBoundingBoxType whether to make the bounding box in aMetrics tight
|
||||
* @param aRefContextForTightBoundingBox a reference context to get the
|
||||
* tight bounding box, if requested
|
||||
* @param aUsedHyphenation if non-null, records if we selected a hyphenation break
|
||||
* @param aLastBreak if non-null and result is aMaxLength, we set this to
|
||||
* the maximal N such that
|
||||
* N < aMaxLength && line break at N && GetAdvanceWidth(aStart, N) <= aWidth
|
||||
* OR N < aMaxLength && hyphen break at N && GetAdvanceWidth(aStart, N) + GetHyphenWidth() <= aWidth
|
||||
* or UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
|
||||
* the effect of
|
||||
* SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
|
||||
*
|
||||
* @param aCanWordWrap true if we can break between any two grapheme
|
||||
* clusters. This is set by word-wrap: break-word
|
||||
*
|
||||
* @param aBreakPriority in/out the priority of the break opportunity
|
||||
* saved in the line. If we are prioritizing break opportunities, we will
|
||||
* not set a break with a lower priority. @see gfxBreakPriority.
|
||||
*
|
||||
* Note that negative advance widths are possible especially if negative
|
||||
* spacing is provided.
|
||||
*/
|
||||
uint32_t BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
||||
bool aLineBreakBefore, gfxFloat aWidth,
|
||||
PropertyProvider *aProvider,
|
||||
bool aSuppressInitialBreak,
|
||||
gfxFloat *aTrimWhitespace,
|
||||
Metrics *aMetrics,
|
||||
gfxFont::BoundingBoxType aBoundingBoxType,
|
||||
gfxContext *aRefContextForTightBoundingBox,
|
||||
bool *aUsedHyphenation,
|
||||
uint32_t *aLastBreak,
|
||||
bool aCanWordWrap,
|
||||
gfxBreakPriority *aBreakPriority);
|
||||
|
||||
/**
|
||||
* Update the reference context.
|
||||
* XXX this is a hack. New text frame does not call this. Use only
|
||||
* temporarily for old text frame.
|
||||
*/
|
||||
void SetContext(gfxContext *aContext) {}
|
||||
|
||||
// Utility getters
|
||||
|
||||
void *GetUserData() const { return mUserData; }
|
||||
void SetUserData(void *aUserData) { mUserData = aUserData; }
|
||||
|
||||
void SetFlagBits(uint32_t aFlags) {
|
||||
NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
|
||||
"Only user flags should be mutable");
|
||||
mFlags |= aFlags;
|
||||
}
|
||||
void ClearFlagBits(uint32_t aFlags) {
|
||||
NS_ASSERTION(!(aFlags & ~gfxTextRunFactory::SETTABLE_FLAGS),
|
||||
"Only user flags should be mutable");
|
||||
mFlags &= ~aFlags;
|
||||
}
|
||||
const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
|
||||
gfxFontGroup *GetFontGroup() const { return mFontGroup; }
|
||||
|
||||
|
||||
// Call this, don't call "new gfxTextRun" directly. This does custom
|
||||
// allocation and initialization
|
||||
static gfxTextRun *Create(const gfxTextRunFactory::Parameters *aParams,
|
||||
uint32_t aLength, gfxFontGroup *aFontGroup,
|
||||
uint32_t aFlags);
|
||||
|
||||
// The text is divided into GlyphRuns as necessary
|
||||
struct GlyphRun {
|
||||
nsRefPtr<gfxFont> mFont; // never null
|
||||
uint32_t mCharacterOffset; // into original UTF16 string
|
||||
uint8_t mMatchType;
|
||||
};
|
||||
|
||||
class GlyphRunIterator {
|
||||
public:
|
||||
GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength)
|
||||
: mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
|
||||
mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
|
||||
}
|
||||
bool NextRun();
|
||||
GlyphRun *GetGlyphRun() { return mGlyphRun; }
|
||||
uint32_t GetStringStart() { return mStringStart; }
|
||||
uint32_t GetStringEnd() { return mStringEnd; }
|
||||
private:
|
||||
gfxTextRun *mTextRun;
|
||||
GlyphRun *mGlyphRun;
|
||||
uint32_t mStringStart;
|
||||
uint32_t mStringEnd;
|
||||
uint32_t mNextIndex;
|
||||
uint32_t mStartOffset;
|
||||
uint32_t mEndOffset;
|
||||
};
|
||||
|
||||
class GlyphRunOffsetComparator {
|
||||
public:
|
||||
bool Equals(const GlyphRun& a,
|
||||
const GlyphRun& b) const
|
||||
{
|
||||
return a.mCharacterOffset == b.mCharacterOffset;
|
||||
}
|
||||
|
||||
bool LessThan(const GlyphRun& a,
|
||||
const GlyphRun& b) const
|
||||
{
|
||||
return a.mCharacterOffset < b.mCharacterOffset;
|
||||
}
|
||||
};
|
||||
|
||||
friend class GlyphRunIterator;
|
||||
friend class FontSelector;
|
||||
|
||||
// API for setting up the textrun glyphs. Should only be called by
|
||||
// things that construct textruns.
|
||||
/**
|
||||
* We've found a run of text that should use a particular font. Call this
|
||||
* only during initialization when font substitution has been computed.
|
||||
* Call it before setting up the glyphs for the characters in this run;
|
||||
* SetMissingGlyph requires that the correct glyphrun be installed.
|
||||
*
|
||||
* If aForceNewRun, a new glyph run will be added, even if the
|
||||
* previously added run uses the same font. If glyph runs are
|
||||
* added out of strictly increasing aStartCharIndex order (via
|
||||
* force), then SortGlyphRuns must be called after all glyph runs
|
||||
* are added before any further operations are performed with this
|
||||
* TextRun.
|
||||
*/
|
||||
nsresult AddGlyphRun(gfxFont *aFont, uint8_t aMatchType,
|
||||
uint32_t aStartCharIndex, bool aForceNewRun);
|
||||
void ResetGlyphRuns() { mGlyphRuns.Clear(); }
|
||||
void SortGlyphRuns();
|
||||
void SanitizeGlyphRuns();
|
||||
|
||||
CompressedGlyph* GetCharacterGlyphs() {
|
||||
NS_ASSERTION(mCharacterGlyphs, "failed to initialize mCharacterGlyphs");
|
||||
return mCharacterGlyphs;
|
||||
}
|
||||
|
||||
// clean out results from shaping in progress, used for fallback scenarios
|
||||
void ClearGlyphsAndCharacters();
|
||||
|
||||
void SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext, uint32_t aCharIndex);
|
||||
|
||||
// Set the glyph data for the given character index to the font's
|
||||
// space glyph, IF this can be done as a "simple" glyph record
|
||||
// (not requiring a DetailedGlyph entry). This avoids the need to call
|
||||
// the font shaper and go through the shaped-word cache for most spaces.
|
||||
//
|
||||
// The parameter aSpaceChar is the original character code for which
|
||||
// this space glyph is being used; if this is U+0020, we need to record
|
||||
// that it could be trimmed at a run edge, whereas other kinds of space
|
||||
// (currently just U+00A0) would not be trimmable/breakable.
|
||||
//
|
||||
// Returns true if it was able to set simple glyph data for the space;
|
||||
// if it returns false, the caller needs to fall back to some other
|
||||
// means to create the necessary (detailed) glyph data.
|
||||
bool SetSpaceGlyphIfSimple(gfxFont *aFont, gfxContext *aContext,
|
||||
uint32_t aCharIndex, char16_t aSpaceChar);
|
||||
|
||||
// Record the positions of specific characters that layout may need to
|
||||
// detect in the textrun, even though it doesn't have an explicit copy
|
||||
// of the original text. These are recorded using flag bits in the
|
||||
// CompressedGlyph record; if necessary, we convert "simple" glyph records
|
||||
// to "complex" ones as the Tab and Newline flags are not present in
|
||||
// simple CompressedGlyph records.
|
||||
void SetIsTab(uint32_t aIndex) {
|
||||
CompressedGlyph *g = &mCharacterGlyphs[aIndex];
|
||||
if (g->IsSimpleGlyph()) {
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
|
||||
details->mGlyphID = g->GetSimpleGlyph();
|
||||
details->mAdvance = g->GetSimpleAdvance();
|
||||
details->mXOffset = details->mYOffset = 0;
|
||||
SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details);
|
||||
}
|
||||
g->SetIsTab();
|
||||
}
|
||||
void SetIsNewline(uint32_t aIndex) {
|
||||
CompressedGlyph *g = &mCharacterGlyphs[aIndex];
|
||||
if (g->IsSimpleGlyph()) {
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
|
||||
details->mGlyphID = g->GetSimpleGlyph();
|
||||
details->mAdvance = g->GetSimpleAdvance();
|
||||
details->mXOffset = details->mYOffset = 0;
|
||||
SetGlyphs(aIndex, CompressedGlyph().SetComplex(true, true, 1), details);
|
||||
}
|
||||
g->SetIsNewline();
|
||||
}
|
||||
void SetIsLowSurrogate(uint32_t aIndex) {
|
||||
SetGlyphs(aIndex, CompressedGlyph().SetComplex(false, false, 0), nullptr);
|
||||
mCharacterGlyphs[aIndex].SetIsLowSurrogate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch all the glyph extents needed to ensure that Measure calls
|
||||
* on this textrun not requesting tight boundingBoxes will succeed. Note
|
||||
* that some glyph extents might not be fetched due to OOM or other
|
||||
* errors.
|
||||
*/
|
||||
void FetchGlyphExtents(gfxContext *aRefContext);
|
||||
|
||||
uint32_t CountMissingGlyphs();
|
||||
const GlyphRun *GetGlyphRuns(uint32_t *aNumGlyphRuns) {
|
||||
*aNumGlyphRuns = mGlyphRuns.Length();
|
||||
return mGlyphRuns.Elements();
|
||||
}
|
||||
// Returns the index of the GlyphRun containing the given offset.
|
||||
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
|
||||
uint32_t FindFirstGlyphRunContaining(uint32_t aOffset);
|
||||
|
||||
// Copy glyph data from a ShapedWord into this textrun.
|
||||
void CopyGlyphDataFrom(gfxShapedWord *aSource, uint32_t aStart);
|
||||
|
||||
// Copy glyph data for a range of characters from aSource to this
|
||||
// textrun.
|
||||
void CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart,
|
||||
uint32_t aLength, uint32_t aDest);
|
||||
|
||||
nsExpirationState *GetExpirationState() { return &mExpirationState; }
|
||||
|
||||
// Tell the textrun to release its reference to its creating gfxFontGroup
|
||||
// immediately, rather than on destruction. This is used for textruns
|
||||
// that are actually owned by a gfxFontGroup, so that they don't keep it
|
||||
// permanently alive due to a circular reference. (The caller of this is
|
||||
// taking responsibility for ensuring the textrun will not outlive its
|
||||
// mFontGroup.)
|
||||
void ReleaseFontGroup();
|
||||
|
||||
struct LigatureData {
|
||||
// textrun offsets of the start and end of the containing ligature
|
||||
uint32_t mLigatureStart;
|
||||
uint32_t mLigatureEnd;
|
||||
// appunits advance to the start of the ligature part within the ligature;
|
||||
// never includes any spacing
|
||||
gfxFloat mPartAdvance;
|
||||
// appunits width of the ligature part; includes before-spacing
|
||||
// when the part is at the start of the ligature, and after-spacing
|
||||
// when the part is as the end of the ligature
|
||||
gfxFloat mPartWidth;
|
||||
|
||||
bool mClipBeforePart;
|
||||
bool mClipAfterPart;
|
||||
};
|
||||
|
||||
// return storage used by this run, for memory reporter;
|
||||
// nsTransformedTextRun needs to override this as it holds additional data
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
MOZ_MUST_OVERRIDE;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
MOZ_MUST_OVERRIDE;
|
||||
|
||||
// Get the size, if it hasn't already been gotten, marking as it goes.
|
||||
size_t MaybeSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
|
||||
if (mFlags & gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED) {
|
||||
return 0;
|
||||
}
|
||||
mFlags |= gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED;
|
||||
return SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
void ResetSizeOfAccountingFlags() {
|
||||
mFlags &= ~gfxTextRunFactory::TEXT_RUN_SIZE_ACCOUNTED;
|
||||
}
|
||||
|
||||
// shaping state - for some font features, fallback is required that
|
||||
// affects the entire run. for example, fallback for one script/font
|
||||
// portion of a textrun requires fallback to be applied to the entire run
|
||||
|
||||
enum ShapingState {
|
||||
eShapingState_Normal, // default state
|
||||
eShapingState_ShapingWithFeature, // have shaped with feature
|
||||
eShapingState_ShapingWithFallback, // have shaped with fallback
|
||||
eShapingState_Aborted, // abort initial iteration
|
||||
eShapingState_ForceFallbackFeature // redo with fallback forced on
|
||||
};
|
||||
|
||||
ShapingState GetShapingState() const { return mShapingState; }
|
||||
void SetShapingState(ShapingState aShapingState) {
|
||||
mShapingState = aShapingState;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void Dump(FILE* aOutput);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Create a textrun, and set its mCharacterGlyphs to point immediately
|
||||
* after the base object; this is ONLY used in conjunction with placement
|
||||
* new, after allocating a block large enough for the glyph records to
|
||||
* follow the base textrun object.
|
||||
*/
|
||||
gfxTextRun(const gfxTextRunFactory::Parameters *aParams,
|
||||
uint32_t aLength, gfxFontGroup *aFontGroup, uint32_t aFlags);
|
||||
|
||||
/**
|
||||
* Helper for the Create() factory method to allocate the required
|
||||
* glyph storage for a textrun object with the basic size aSize,
|
||||
* plus room for aLength glyph records.
|
||||
*/
|
||||
static void* AllocateStorageForTextRun(size_t aSize, uint32_t aLength);
|
||||
|
||||
// Pointer to the array of CompressedGlyph records; must be initialized
|
||||
// when the object is constructed.
|
||||
CompressedGlyph *mCharacterGlyphs;
|
||||
|
||||
private:
|
||||
// **** general helpers ****
|
||||
|
||||
// Get the total advance for a range of glyphs.
|
||||
int32_t GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd);
|
||||
|
||||
// Spacing for characters outside the range aSpacingStart/aSpacingEnd
|
||||
// is assumed to be zero; such characters are not passed to aProvider.
|
||||
// This is useful to protect aProvider from being passed character indices
|
||||
// it is not currently able to handle.
|
||||
bool GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd,
|
||||
PropertyProvider *aProvider,
|
||||
uint32_t aSpacingStart, uint32_t aSpacingEnd,
|
||||
nsTArray<PropertyProvider::Spacing> *aSpacing);
|
||||
|
||||
// **** ligature helpers ****
|
||||
// (Platforms do the actual ligaturization, but we need to do a bunch of stuff
|
||||
// to handle requests that begin or end inside a ligature)
|
||||
|
||||
// if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
|
||||
LigatureData ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd,
|
||||
PropertyProvider *aProvider);
|
||||
gfxFloat ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd,
|
||||
PropertyProvider *aProvider);
|
||||
void DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
|
||||
gfxPoint *aPt, PropertyProvider *aProvider,
|
||||
TextRunDrawParams& aParams);
|
||||
// Advance aStart to the start of the nearest ligature; back up aEnd
|
||||
// to the nearest ligature end; may result in *aStart == *aEnd
|
||||
void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd);
|
||||
// result in appunits
|
||||
gfxFloat GetPartialLigatureWidth(uint32_t aStart, uint32_t aEnd, PropertyProvider *aProvider);
|
||||
void AccumulatePartialLigatureMetrics(gfxFont *aFont,
|
||||
uint32_t aStart, uint32_t aEnd,
|
||||
gfxFont::BoundingBoxType aBoundingBoxType,
|
||||
gfxContext *aRefContext,
|
||||
PropertyProvider *aProvider,
|
||||
Metrics *aMetrics);
|
||||
|
||||
// **** measurement helper ****
|
||||
void AccumulateMetricsForRun(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
|
||||
gfxFont::BoundingBoxType aBoundingBoxType,
|
||||
gfxContext *aRefContext,
|
||||
PropertyProvider *aProvider,
|
||||
uint32_t aSpacingStart, uint32_t aSpacingEnd,
|
||||
Metrics *aMetrics);
|
||||
|
||||
// **** drawing helper ****
|
||||
void DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
|
||||
gfxPoint *aPt, PropertyProvider *aProvider,
|
||||
uint32_t aSpacingStart, uint32_t aSpacingEnd,
|
||||
TextRunDrawParams& aParams);
|
||||
|
||||
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
|
||||
// for smaller size especially in the super-common one-glyphrun case
|
||||
nsAutoTArray<GlyphRun,1> mGlyphRuns;
|
||||
|
||||
void *mUserData;
|
||||
gfxFontGroup *mFontGroup; // addrefed on creation, but our reference
|
||||
// may be released by ReleaseFontGroup()
|
||||
gfxSkipChars mSkipChars;
|
||||
nsExpirationState mExpirationState;
|
||||
|
||||
bool mSkipDrawing; // true if the font group we used had a user font
|
||||
// download that's in progress, so we should hide text
|
||||
// until the download completes (or timeout fires)
|
||||
bool mReleasedFontGroup; // we already called NS_RELEASE on
|
||||
// mFontGroup, so don't do it again
|
||||
|
||||
// shaping state for handling variant fallback features
|
||||
// such as subscript/superscript variant glyphs
|
||||
ShapingState mShapingState;
|
||||
};
|
||||
|
||||
class gfxFontGroup : public gfxTextRunFactory {
|
||||
public:
|
||||
class FamilyFace {
|
||||
public:
|
||||
FamilyFace() { }
|
||||
|
||||
FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont)
|
||||
: mFamily(aFamily), mFont(aFont)
|
||||
{
|
||||
NS_ASSERTION(aFont, "font pointer must not be null");
|
||||
NS_ASSERTION(!aFamily ||
|
||||
aFamily->ContainsFace(aFont->GetFontEntry()),
|
||||
"font is not a member of the given family");
|
||||
}
|
||||
|
||||
gfxFontFamily* Family() const { return mFamily.get(); }
|
||||
gfxFont* Font() const { return mFont.get(); }
|
||||
|
||||
private:
|
||||
nsRefPtr<gfxFontFamily> mFamily;
|
||||
nsRefPtr<gfxFont> mFont;
|
||||
};
|
||||
|
||||
static void Shutdown(); // platform must call this to release the languageAtomService
|
||||
|
||||
gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
|
||||
const gfxFontStyle *aStyle,
|
||||
gfxUserFontSet *aUserFontSet = nullptr);
|
||||
|
||||
virtual ~gfxFontGroup();
|
||||
|
||||
virtual gfxFont *GetFontAt(int32_t i) {
|
||||
// If it turns out to be hard for all clients that cache font
|
||||
// groups to call UpdateFontList at appropriate times, we could
|
||||
// instead consider just calling UpdateFontList from someplace
|
||||
// more central (such as here).
|
||||
NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
|
||||
"Whoever was caching this font group should have "
|
||||
"called UpdateFontList on it");
|
||||
NS_ASSERTION(mFonts.Length() > uint32_t(i) && mFonts[i].Font(),
|
||||
"Requesting a font index that doesn't exist");
|
||||
|
||||
return mFonts[i].Font();
|
||||
}
|
||||
|
||||
// Returns the first font in the font-group that has an OpenType MATH table,
|
||||
// or null if no such font is available. The GetMathConstant methods may be
|
||||
// called on the returned font.
|
||||
gfxFont *GetFirstMathFont();
|
||||
|
||||
uint32_t FontListLength() const {
|
||||
return mFonts.Length();
|
||||
}
|
||||
|
||||
const gfxFontStyle *GetStyle() const { return &mStyle; }
|
||||
|
||||
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
|
||||
|
||||
/**
|
||||
* The listed characters should be treated as invisible and zero-width
|
||||
* when creating textruns.
|
||||
*/
|
||||
static bool IsInvalidChar(uint8_t ch);
|
||||
static bool IsInvalidChar(char16_t ch);
|
||||
|
||||
/**
|
||||
* Make a textrun for a given string.
|
||||
* If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
|
||||
* textrun will copy it.
|
||||
* This calls FetchGlyphExtents on the textrun.
|
||||
*/
|
||||
virtual gfxTextRun *MakeTextRun(const char16_t *aString, uint32_t aLength,
|
||||
const Parameters *aParams, uint32_t aFlags);
|
||||
/**
|
||||
* Make a textrun for a given string.
|
||||
* If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
|
||||
* textrun will copy it.
|
||||
* This calls FetchGlyphExtents on the textrun.
|
||||
*/
|
||||
virtual gfxTextRun *MakeTextRun(const uint8_t *aString, uint32_t aLength,
|
||||
const Parameters *aParams, uint32_t aFlags);
|
||||
|
||||
/**
|
||||
* Textrun creation helper for clients that don't want to pass
|
||||
* a full Parameters record.
|
||||
*/
|
||||
template<typename T>
|
||||
gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength,
|
||||
gfxContext *aRefContext,
|
||||
int32_t aAppUnitsPerDevUnit,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
gfxTextRunFactory::Parameters params = {
|
||||
aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit
|
||||
};
|
||||
return MakeTextRun(aString, aLength, ¶ms, aFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (possibly-cached) width of the hyphen character.
|
||||
* The aCtx and aAppUnitsPerDevUnit parameters will be used only if
|
||||
* needed to initialize the cached hyphen width; otherwise they are
|
||||
* ignored.
|
||||
*/
|
||||
gfxFloat GetHyphenWidth(gfxTextRun::PropertyProvider* aProvider);
|
||||
|
||||
/**
|
||||
* Make a text run representing a single hyphen character.
|
||||
* This will use U+2010 HYPHEN if available in the first font,
|
||||
* otherwise fall back to U+002D HYPHEN-MINUS.
|
||||
* The caller is responsible for deleting the returned text run
|
||||
* when no longer required.
|
||||
*/
|
||||
gfxTextRun *MakeHyphenTextRun(gfxContext *aCtx,
|
||||
uint32_t aAppUnitsPerDevUnit);
|
||||
|
||||
/**
|
||||
* Check whether a given font (specified by its gfxFontEntry)
|
||||
* is already in the fontgroup's list of actual fonts
|
||||
*/
|
||||
bool HasFont(const gfxFontEntry *aFontEntry);
|
||||
|
||||
// This returns the preferred underline for this font group.
|
||||
// Some CJK fonts have wrong underline offset in its metrics.
|
||||
// If this group has such "bad" font, each platform's gfxFontGroup initialized mUnderlineOffset.
|
||||
// The value should be lower value of first font's metrics and the bad font's metrics.
|
||||
// Otherwise, this returns from first font's metrics.
|
||||
enum { UNDERLINE_OFFSET_NOT_SET = INT16_MAX };
|
||||
virtual gfxFloat GetUnderlineOffset() {
|
||||
if (mUnderlineOffset == UNDERLINE_OFFSET_NOT_SET)
|
||||
mUnderlineOffset = GetFontAt(0)->GetMetrics().underlineOffset;
|
||||
return mUnderlineOffset;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<gfxFont>
|
||||
FindFontForChar(uint32_t ch, uint32_t prevCh, int32_t aRunScript,
|
||||
gfxFont *aPrevMatchedFont,
|
||||
uint8_t *aMatchType);
|
||||
|
||||
// search through pref fonts for a character, return nullptr if no matching pref font
|
||||
virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
|
||||
|
||||
virtual already_AddRefed<gfxFont>
|
||||
WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript);
|
||||
|
||||
template<typename T>
|
||||
void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
|
||||
const T *aString, uint32_t aLength,
|
||||
int32_t aRunScript);
|
||||
|
||||
gfxUserFontSet* GetUserFontSet();
|
||||
|
||||
// With downloadable fonts, the composition of the font group can change as fonts are downloaded
|
||||
// for each change in state of the user font set, the generation value is bumped to avoid picking up
|
||||
// previously created text runs in the text run word cache. For font groups based on stylesheets
|
||||
// with no @font-face rule, this always returns 0.
|
||||
uint64_t GetGeneration();
|
||||
|
||||
// used when logging text performance
|
||||
gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; }
|
||||
void SetTextPerfMetrics(gfxTextPerfMetrics *aTextPerf) { mTextPerf = aTextPerf; }
|
||||
|
||||
// This will call UpdateFontList() if the user font set is changed.
|
||||
void SetUserFontSet(gfxUserFontSet *aUserFontSet);
|
||||
|
||||
// If there is a user font set, check to see whether the font list or any
|
||||
// caches need updating.
|
||||
virtual void UpdateFontList();
|
||||
|
||||
bool ShouldSkipDrawing() const {
|
||||
return mSkipDrawing;
|
||||
}
|
||||
|
||||
class LazyReferenceContextGetter {
|
||||
public:
|
||||
virtual already_AddRefed<gfxContext> GetRefContext() = 0;
|
||||
};
|
||||
// The gfxFontGroup keeps ownership of this textrun.
|
||||
// It is only guaranteed to exist until the next call to GetEllipsisTextRun
|
||||
// (which might use a different appUnitsPerDev value) for the font group,
|
||||
// or until UpdateFontList is called, or the fontgroup is destroyed.
|
||||
// Get it/use it/forget it :) - don't keep a reference that might go stale.
|
||||
gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
|
||||
LazyReferenceContextGetter& aRefContextGetter);
|
||||
|
||||
// helper method for resolving generic font families
|
||||
static void
|
||||
ResolveGenericFontNames(mozilla::FontFamilyType aGenericType,
|
||||
nsIAtom *aLanguage,
|
||||
nsTArray<nsString>& aGenericFamilies);
|
||||
|
||||
protected:
|
||||
mozilla::FontFamilyList mFamilyList;
|
||||
gfxFontStyle mStyle;
|
||||
nsTArray<FamilyFace> mFonts;
|
||||
gfxFloat mUnderlineOffset;
|
||||
gfxFloat mHyphenWidth;
|
||||
|
||||
nsRefPtr<gfxUserFontSet> mUserFontSet;
|
||||
uint64_t mCurrGeneration; // track the current user font set generation, rebuild font list if needed
|
||||
|
||||
gfxTextPerfMetrics *mTextPerf;
|
||||
|
||||
// Cache a textrun representing an ellipsis (useful for CSS text-overflow)
|
||||
// at a specific appUnitsPerDevPixel size
|
||||
nsAutoPtr<gfxTextRun> mCachedEllipsisTextRun;
|
||||
|
||||
// cache the most recent pref font to avoid general pref font lookup
|
||||
nsRefPtr<gfxFontFamily> mLastPrefFamily;
|
||||
nsRefPtr<gfxFont> mLastPrefFont;
|
||||
eFontPrefLang mLastPrefLang; // lang group for last pref font
|
||||
eFontPrefLang mPageLang;
|
||||
bool mLastPrefFirstFont; // is this the first font in the list of pref fonts for this lang group?
|
||||
|
||||
bool mSkipDrawing; // hide text while waiting for a font
|
||||
// download to complete (or fallback
|
||||
// timer to fire)
|
||||
|
||||
/**
|
||||
* Textrun creation short-cuts for special cases where we don't need to
|
||||
* call a font shaper to generate glyphs.
|
||||
*/
|
||||
gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags);
|
||||
gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags);
|
||||
gfxTextRun *MakeBlankTextRun(uint32_t aLength,
|
||||
const Parameters *aParams, uint32_t aFlags);
|
||||
|
||||
// Initialize the list of fonts
|
||||
void BuildFontList();
|
||||
|
||||
// Init this font group's font metrics. If there no bad fonts, you don't need to call this.
|
||||
// But if there are one or more bad fonts which have bad underline offset,
|
||||
// you should call this with the *first* bad font.
|
||||
void InitMetricsForBadFont(gfxFont* aBadFont);
|
||||
|
||||
// Set up the textrun glyphs for an entire text run:
|
||||
// find script runs, and then call InitScriptRun for each
|
||||
template<typename T>
|
||||
void InitTextRun(gfxContext *aContext,
|
||||
gfxTextRun *aTextRun,
|
||||
const T *aString,
|
||||
uint32_t aLength);
|
||||
|
||||
// InitTextRun helper to handle a single script run, by finding font ranges
|
||||
// and calling each font's InitTextRun() as appropriate
|
||||
template<typename T>
|
||||
void InitScriptRun(gfxContext *aContext,
|
||||
gfxTextRun *aTextRun,
|
||||
const T *aString,
|
||||
uint32_t aScriptRunStart,
|
||||
uint32_t aScriptRunEnd,
|
||||
int32_t aRunScript);
|
||||
|
||||
// Helper for font-matching:
|
||||
// see if aCh is supported in any of the faces from aFamily;
|
||||
// if so return the best style match, else return null.
|
||||
already_AddRefed<gfxFont> TryAllFamilyMembers(gfxFontFamily* aFamily,
|
||||
uint32_t aCh);
|
||||
|
||||
// helper methods for looking up fonts
|
||||
|
||||
// iterate over the fontlist, lookup names and expand generics
|
||||
void EnumerateFontList(nsIAtom *aLanguage, void *aClosure = nullptr);
|
||||
|
||||
// expand a generic to a list of specific names based on prefs
|
||||
void FindGenericFonts(mozilla::FontFamilyType aGenericType,
|
||||
nsIAtom *aLanguage,
|
||||
void *aClosure);
|
||||
|
||||
// lookup and add a font with a given name (i.e. *not* a generic!)
|
||||
virtual void FindPlatformFont(const nsAString& aName,
|
||||
bool aUseFontSet,
|
||||
void *aClosure);
|
||||
|
||||
static nsILanguageAtomService* gLangService;
|
||||
};
|
||||
#endif
|
|
@ -43,6 +43,7 @@
|
|||
#include <dwrite.h>
|
||||
#endif
|
||||
|
||||
#include "gfxTextRun.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
|
|
@ -18,6 +18,7 @@ EXPORTS += [
|
|||
'gfxFailure.h',
|
||||
'gfxFont.h',
|
||||
'gfxFontConstants.h',
|
||||
'gfxFontEntry.h',
|
||||
'gfxFontFamilyList.h',
|
||||
'gfxFontFeatures.h',
|
||||
'gfxFontInfoLoader.h',
|
||||
|
@ -43,6 +44,7 @@ EXPORTS += [
|
|||
'gfxSkipChars.h',
|
||||
'gfxSVGGlyphs.h',
|
||||
'gfxTeeSurface.h',
|
||||
'gfxTextRun.h',
|
||||
'gfxTypes.h',
|
||||
'gfxUserFontSet.h',
|
||||
'gfxUtils.h',
|
||||
|
@ -205,6 +207,8 @@ SOURCES += [
|
|||
# Uses FORCE_PR_LOG
|
||||
'gfxFont.cpp',
|
||||
# Uses FORCE_PR_LOG
|
||||
'gfxFontEntry.cpp',
|
||||
# Uses FORCE_PR_LOG
|
||||
'gfxFontUtils.cpp',
|
||||
# Includes mac system header conflicting with point/size, and also uses FORCE_PR_LOG
|
||||
'gfxPlatform.cpp',
|
||||
|
@ -226,6 +230,7 @@ UNIFIED_SOURCES += [
|
|||
'gfxFontInfoLoader.cpp',
|
||||
'gfxFontMissingGlyphs.cpp',
|
||||
'gfxFontTest.cpp',
|
||||
'gfxGlyphExtents.cpp',
|
||||
'gfxGradientCache.cpp',
|
||||
'gfxGraphiteShaper.cpp',
|
||||
'gfxHarfBuzzShaper.cpp',
|
||||
|
@ -240,6 +245,7 @@ UNIFIED_SOURCES += [
|
|||
'gfxSkipChars.cpp',
|
||||
'gfxSVGGlyphs.cpp',
|
||||
'gfxTeeSurface.cpp',
|
||||
'gfxTextRun.cpp',
|
||||
'gfxUtils.cpp',
|
||||
'nsSurfaceTexture.cpp',
|
||||
'nsUnicodeRange.cpp',
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
* 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/. */
|
||||
|
||||
#ifndef NS_UNICODERANGE_H
|
||||
#define NS_UNICODERANGE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class nsIAtom;
|
||||
|
@ -87,3 +90,5 @@ const uint8_t kRangeTertiaryTable = 145; // leave room for 16 subtable
|
|||
|
||||
uint32_t FindCharUnicodeRange(uint32_t ch);
|
||||
nsIAtom* LangGroupFromUnicodeRange(uint8_t unicodeRange);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#include "gfxFont.h"
|
||||
#include "gfxContext.h"
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include "nsFrame.h"
|
||||
#include "nsSplittableFrame.h"
|
||||
#include "nsLineBox.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxSkipChars.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
||||
class nsTextPaintStyle;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "nsStyleContext.h"
|
||||
|
||||
class nsTransformedTextRun;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "nsFontFace.h"
|
||||
#include "nsIDOMCSSFontFaceRule.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "nsFontFaceLoader.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "nsFontFace.h"
|
||||
#include "nsFontFaceLoader.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
nsFontFaceList::nsFontFaceList()
|
||||
|
|
Загрузка…
Ссылка в новой задаче