Bug 619521 - Part 1: Send a notification of any scripts for which font coverage is lacking. r=jdaggett

This commit is contained in:
Jonathan Kew 2014-12-22 16:35:54 +00:00
parent 1d3e35e67b
commit 65c4ca0e3f
14 changed files with 254 additions and 49 deletions

View File

@ -3252,6 +3252,22 @@ CanvasRenderingContext2D::GetHitRegionRect(Element* aElement, nsRect& aRect)
*/
struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor
{
CanvasBidiProcessor()
: nsBidiPresUtils::BidiProcessor()
{
if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) {
mMissingFonts = new gfxMissingFontRecorder();
}
}
~CanvasBidiProcessor()
{
// notify front-end code if we encountered missing glyphs in any script
if (mMissingFonts) {
mMissingFonts->Flush();
}
}
typedef CanvasRenderingContext2D::ContextState ContextState;
virtual void SetText(const char16_t* text, int32_t length, nsBidiDirection direction)
@ -3268,7 +3284,8 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
length,
mThebes,
mAppUnitsPerDevPixel,
flags);
flags,
mMissingFonts);
}
virtual nscoord GetWidth()
@ -3514,6 +3531,10 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
// current font
gfxFontGroup* mFontgrp;
// to record any unsupported characters found in the text,
// and notify front-end if it is interested
nsAutoPtr<gfxMissingFontRecorder> mMissingFonts;
// dev pixel conversion factor
int32_t mAppUnitsPerDevPixel;

View File

@ -33,7 +33,8 @@ public:
reinterpret_cast<const uint8_t*>(aString), aLength,
aRC->ThebesContext(),
aMetrics->AppUnitsPerDevPixel(),
ComputeFlags(aMetrics));
ComputeFlags(aMetrics),
nullptr);
}
AutoTextRun(nsFontMetrics* aMetrics, nsRenderingContext* aRC,
@ -43,7 +44,8 @@ public:
aString, aLength,
aRC->ThebesContext(),
aMetrics->AppUnitsPerDevPixel(),
ComputeFlags(aMetrics));
ComputeFlags(aMetrics),
nullptr);
}
gfxTextRun *get() { return mTextRun; }

View File

@ -28,6 +28,7 @@
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::unicode;
using mozilla::services::GetObserverService;
static const char16_t kEllipsisChar[] = { 0x2026, 0x0 };
static const char16_t kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 };
@ -2039,12 +2040,12 @@ gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
gfxFont *font = GetFirstValidFont(uint32_t(hyphen));
if (font->HasCharacter(hyphen)) {
return MakeTextRun(&hyphen, 1, aCtx, aAppUnitsPerDevUnit,
gfxFontGroup::TEXT_IS_PERSISTENT);
gfxFontGroup::TEXT_IS_PERSISTENT, nullptr);
}
static const uint8_t dash = '-';
return MakeTextRun(&dash, 1, aCtx, aAppUnitsPerDevUnit,
gfxFontGroup::TEXT_IS_PERSISTENT);
gfxFontGroup::TEXT_IS_PERSISTENT, nullptr);
}
gfxFloat
@ -2065,7 +2066,8 @@ gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider)
gfxTextRun *
gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength,
const Parameters *aParams, uint32_t aFlags)
const Parameters *aParams, uint32_t aFlags,
gfxMissingFontRecorder *aMFR)
{
if (aLength == 0) {
return MakeEmptyTextRun(aParams, aFlags);
@ -2089,7 +2091,7 @@ gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength,
return nullptr;
}
InitTextRun(aParams->mContext, textRun, aString, aLength);
InitTextRun(aParams->mContext, textRun, aString, aLength, aMFR);
textRun->FetchGlyphExtents(aParams->mContext);
@ -2098,7 +2100,8 @@ gfxFontGroup::MakeTextRun(const uint8_t *aString, uint32_t aLength,
gfxTextRun *
gfxFontGroup::MakeTextRun(const char16_t *aString, uint32_t aLength,
const Parameters *aParams, uint32_t aFlags)
const Parameters *aParams, uint32_t aFlags,
gfxMissingFontRecorder *aMFR)
{
if (aLength == 0) {
return MakeEmptyTextRun(aParams, aFlags);
@ -2116,7 +2119,7 @@ gfxFontGroup::MakeTextRun(const char16_t *aString, uint32_t aLength,
return nullptr;
}
InitTextRun(aParams->mContext, textRun, aString, aLength);
InitTextRun(aParams->mContext, textRun, aString, aLength, aMFR);
textRun->FetchGlyphExtents(aParams->mContext);
@ -2128,7 +2131,8 @@ void
gfxFontGroup::InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const T *aString,
uint32_t aLength)
uint32_t aLength,
gfxMissingFontRecorder *aMFR)
{
NS_ASSERTION(aLength > 0, "don't call InitTextRun for a zero-length run");
@ -2208,7 +2212,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext,
// the text is still purely 8-bit; bypass the script-run itemizer
// and treat it as a single Latin run
InitScriptRun(aContext, aTextRun, aString,
0, aLength, MOZ_SCRIPT_LATIN);
0, aLength, MOZ_SCRIPT_LATIN, aMFR);
} else {
const char16_t *textPtr;
if (transformedString) {
@ -2256,7 +2260,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext,
#endif
InitScriptRun(aContext, aTextRun, textPtr + runStart,
runStart, runLimit - runStart, runScript);
runStart, runLimit - runStart, runScript, aMFR);
}
}
@ -2292,6 +2296,14 @@ gfxFontGroup::InitTextRun(gfxContext *aContext,
aTextRun->SortGlyphRuns();
}
static inline bool
IsPUA(uint32_t aUSV)
{
// We could look up the General Category of the codepoint here,
// but it's simpler to check PUA codepoint ranges.
return (aUSV >= 0xE000 && aUSV <= 0xF8FF) || (aUSV >= 0xF0000);
}
template<typename T>
void
gfxFontGroup::InitScriptRun(gfxContext *aContext,
@ -2301,7 +2313,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
uint32_t aOffset, // position of the script run
// within the textrun
uint32_t aLength, // length of the script run
int32_t aRunScript)
int32_t aRunScript,
gfxMissingFontRecorder *aMFR)
{
NS_ASSERTION(aLength > 0, "don't call InitScriptRun for a 0-length run");
NS_ASSERTION(aTextRun->GetShapingState() != gfxTextRun::eShapingState_Aborted,
@ -2322,6 +2335,7 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
ComputeRanges(fontRanges, aString, aLength, aRunScript,
aTextRun->GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK);
uint32_t numRanges = fontRanges.Length();
bool missingChars = false;
for (uint32_t r = 0; r < numRanges; r++) {
const gfxTextRange& range = fontRanges[r];
@ -2468,11 +2482,15 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
index + 1 < aLength &&
NS_IS_LOW_SURROGATE(aString[index + 1]))
{
uint32_t usv =
SURROGATE_TO_UCS4(ch, aString[index + 1]);
aTextRun->SetMissingGlyph(aOffset + index,
SURROGATE_TO_UCS4(ch,
aString[index + 1]),
usv,
mainFont);
index++;
if (!mSkipDrawing && !IsPUA(usv)) {
missingChars = true;
}
continue;
}
@ -2507,11 +2525,18 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
// record char code so we can draw a box with the Unicode value
aTextRun->SetMissingGlyph(aOffset + index, ch, mainFont);
if (!mSkipDrawing && !IsPUA(ch)) {
missingChars = true;
}
}
}
runStart += matchedLength;
}
if (aMFR && missingChars) {
aMFR->RecordScript(aRunScript);
}
}
gfxTextRun *
@ -2537,7 +2562,8 @@ gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
refCtx, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel
};
gfxTextRun* textRun =
MakeTextRun(ellipsis.get(), ellipsis.Length(), &params, TEXT_IS_PERSISTENT);
MakeTextRun(ellipsis.get(), ellipsis.Length(), &params,
TEXT_IS_PERSISTENT, nullptr);
if (!textRun) {
return nullptr;
}
@ -3109,3 +3135,41 @@ gfxFontGroup::Shutdown()
}
nsILanguageAtomService* gfxFontGroup::gLangService = nullptr;
void
gfxMissingFontRecorder::Flush()
{
static bool mNotifiedFontsInitialized = false;
static uint32_t mNotifiedFonts[gfxMissingFontRecorder::kNumScriptBitsWords];
if (!mNotifiedFontsInitialized) {
memset(&mNotifiedFonts, 0, sizeof(mNotifiedFonts));
mNotifiedFontsInitialized = true;
}
nsAutoString fontNeeded;
for (uint32_t i = 0; i < kNumScriptBitsWords; ++i) {
mMissingFonts[i] &= ~mNotifiedFonts[i];
if (!mMissingFonts[i]) {
continue;
}
for (uint32_t j = 0; j < 32; ++j) {
if (!(mMissingFonts[i] & (1 << j))) {
continue;
}
mNotifiedFonts[i] |= (1 << j);
if (!fontNeeded.IsEmpty()) {
fontNeeded.Append(PRUnichar(','));
}
uint32_t tag = GetScriptTagForCode(i * 32 + j);
fontNeeded.Append(char16_t(tag >> 24));
fontNeeded.Append(char16_t((tag >> 16) & 0xff));
fontNeeded.Append(char16_t((tag >> 8) & 0xff));
fontNeeded.Append(char16_t(tag & 0xff));
}
mMissingFonts[i] = 0;
}
if (!fontNeeded.IsEmpty()) {
nsCOMPtr<nsIObserverService> service = GetObserverService();
service->NotifyObservers(nullptr, "font-needed", fontNeeded.get());
}
}

View File

@ -16,6 +16,7 @@
#include "mozilla/MemoryReporting.h"
#include "DrawMode.h"
#include "harfbuzz/hb.h"
#include "nsUnicodeScriptCodes.h"
#ifdef DEBUG
#include <stdio.h>
@ -27,6 +28,7 @@ class gfxUserFontSet;
class gfxTextContextPaint;
class nsIAtom;
class nsILanguageAtomService;
class gfxMissingFontRecorder;
/**
* Callback for Draw() to use when drawing text with mode
@ -769,7 +771,8 @@ public:
* This calls FetchGlyphExtents on the textrun.
*/
virtual gfxTextRun *MakeTextRun(const char16_t *aString, uint32_t aLength,
const Parameters *aParams, uint32_t aFlags);
const Parameters *aParams, uint32_t aFlags,
gfxMissingFontRecorder *aMFR);
/**
* Make a textrun for a given string.
* If aText is not persistent (aFlags & TEXT_IS_PERSISTENT), the
@ -777,7 +780,8 @@ public:
* This calls FetchGlyphExtents on the textrun.
*/
virtual gfxTextRun *MakeTextRun(const uint8_t *aString, uint32_t aLength,
const Parameters *aParams, uint32_t aFlags);
const Parameters *aParams, uint32_t aFlags,
gfxMissingFontRecorder *aMFR);
/**
* Textrun creation helper for clients that don't want to pass
@ -787,12 +791,13 @@ public:
gfxTextRun *MakeTextRun(const T *aString, uint32_t aLength,
gfxContext *aRefContext,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags)
uint32_t aFlags,
gfxMissingFontRecorder *aMFR)
{
gfxTextRunFactory::Parameters params = {
aRefContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevUnit
};
return MakeTextRun(aString, aLength, &params, aFlags);
return MakeTextRun(aString, aLength, &params, aFlags, aMFR);
}
/**
@ -1088,7 +1093,8 @@ protected:
void InitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const T *aString,
uint32_t aLength);
uint32_t aLength,
gfxMissingFontRecorder *aMFR);
// InitTextRun helper to handle a single script run, by finding font ranges
// and calling each font's InitTextRun() as appropriate
@ -1098,7 +1104,8 @@ protected:
const T *aString,
uint32_t aScriptRunStart,
uint32_t aScriptRunEnd,
int32_t aRunScript);
int32_t aRunScript,
gfxMissingFontRecorder *aMFR);
// Helper for font-matching:
// When matching the italic case, allow use of the regular face
@ -1124,4 +1131,56 @@ protected:
static nsILanguageAtomService* gLangService;
};
// A "missing font recorder" is to be used during text-run creation to keep
// a record of any scripts encountered for which font coverage was lacking;
// when Flush() is called, it sends a notification that front-end code can use
// to download fonts on demand (or whatever else it wants to do).
#define GFX_MISSING_FONTS_NOTIFY_PREF "gfx.missing_fonts.notify"
class gfxMissingFontRecorder {
public:
gfxMissingFontRecorder()
{
MOZ_COUNT_CTOR(gfxMissingFontRecorder);
memset(&mMissingFonts, 0, sizeof(mMissingFonts));
}
~gfxMissingFontRecorder()
{
#ifdef DEBUG
for (uint32_t i = 0; i < kNumScriptBitsWords; i++) {
NS_ASSERTION(mMissingFonts[i] == 0,
"failed to flush the missing-font recorder");
}
#endif
MOZ_COUNT_DTOR(gfxMissingFontRecorder);
}
// record this script code in our mMissingFonts bitset
void RecordScript(int32_t aScriptCode)
{
mMissingFonts[uint32_t(aScriptCode) >> 5] |=
(1 << (uint32_t(aScriptCode) & 0x1f));
}
// send a notification of any missing-scripts that have been
// recorded, and clear the mMissingFonts set for re-use
void Flush();
// forget any missing-scripts that have been recorded up to now;
// called before discarding a recorder we no longer care about
void Clear()
{
memset(&mMissingFonts, 0, sizeof(mMissingFonts));
}
private:
// Number of 32-bit words needed for the missing-script flags
static const uint32_t kNumScriptBitsWords =
((MOZ_NUM_SCRIPT_CODES + 31) / 32);
uint32_t mMissingFonts[kNumScriptBitsWords];
};
#endif

View File

@ -64,6 +64,7 @@
#include "nsContentUtils.h"
#include "nsPIWindowRoot.h"
#include "mozilla/Preferences.h"
#include "gfxTextRun.h"
// Needed for Start/Stop of Image Animation
#include "imgIContainer.h"
@ -249,6 +250,10 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
if (log && log->level >= PR_LOG_WARNING) {
mTextPerf = new gfxTextPerfMetrics();
}
if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) {
mMissingFonts = new gfxMissingFontRecorder();
}
}
void
@ -341,6 +346,9 @@ nsPresContext::LastRelease()
if (IsRoot()) {
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
}
if (mMissingFonts) {
mMissingFonts->Clear();
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
@ -873,6 +881,20 @@ nsPresContext::PreferenceChanged(const char* aPrefName)
}
return;
}
if (prefName.EqualsLiteral(GFX_MISSING_FONTS_NOTIFY_PREF)) {
if (Preferences::GetBool(GFX_MISSING_FONTS_NOTIFY_PREF)) {
if (!mMissingFonts) {
mMissingFonts = new gfxMissingFontRecorder();
// trigger reflow to detect missing fonts on the current page
mPrefChangePendingNeedsReflow = true;
}
} else {
if (mMissingFonts) {
mMissingFonts->Clear();
}
mMissingFonts = nullptr;
}
}
if (StringBeginsWith(prefName, NS_LITERAL_CSTRING("font."))) {
// Changes to font family preferences don't change anything in the
// computed style data, so the style system won't generate a reflow
@ -2194,6 +2216,14 @@ nsPresContext::RebuildCounterStyles()
}
}
void
nsPresContext::NotifyMissingFonts()
{
if (mMissingFonts) {
mMissingFonts->Flush();
}
}
void
nsPresContext::EnsureSafeToHandOutCSSRules()
{

View File

@ -65,6 +65,7 @@ class nsAnimationManager;
class nsRefreshDriver;
class nsIWidget;
class nsDeviceContext;
class gfxMissingFontRecorder;
namespace mozilla {
class EventStateManager;
@ -876,6 +877,9 @@ public:
// user font set is changed and fonts become unavailable).
void UserFontSetUpdated();
gfxMissingFontRecorder *MissingFontRecorder() { return mMissingFonts; }
void NotifyMissingFonts();
mozilla::dom::FontFaceSet* Fonts();
void FlushCounterStyles();
@ -1251,6 +1255,8 @@ protected:
// text performance metrics
nsAutoPtr<gfxTextPerfMetrics> mTextPerf;
nsAutoPtr<gfxMissingFontRecorder> mMissingFonts;
nsRect mVisibleArea;
nsSize mPageSize;
float mPageScale;

View File

@ -9119,6 +9119,8 @@ PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted)
mTouchCaret->UpdatePositionIfNeeded();
}
mPresContext->NotifyMissingFonts();
if (!aWasInterrupted) {
ClearReflowOnZoomPending();
}

View File

@ -529,7 +529,8 @@ MathVariant(uint32_t aCh, uint8_t aMathVar)
void
MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
gfxContext* aRefContext)
gfxContext* aRefContext,
gfxMissingFontRecorder* aMFR)
{
gfxFontGroup* fontGroup = aTextRun->GetFontGroup();
@ -766,7 +767,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
} else {
cachedChild = newFontGroup->MakeTextRun(
convertedString.BeginReading(), convertedString.Length(),
&innerParams, flags);
&innerParams, flags, aMFR);
child = cachedChild.get();
}
if (!child)
@ -778,7 +779,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
canBreakBeforeArray.Elements(), aRefContext);
if (transformedChild) {
transformedChild->FinishSettingProperties(aRefContext);
transformedChild->FinishSettingProperties(aRefContext, aMFR);
}
if (mergeNeeded) {

View File

@ -22,7 +22,8 @@ public:
mSSTYScriptLevel(aSSTYScriptLevel) {}
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
gfxContext* aRefContext) MOZ_OVERRIDE;
gfxContext* aRefContext,
gfxMissingFontRecorder* aMFR) MOZ_OVERRIDE;
enum {
// Style effects which may override single character <mi> behaviour
MATH_FONT_STYLING_NORMAL = 0x1, // fontstyle="normal" has been set.

View File

@ -561,10 +561,11 @@ template<typename T>
gfxTextRun *
MakeTextRun(const T *aText, uint32_t aLength,
gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams,
uint32_t aFlags)
uint32_t aFlags, gfxMissingFontRecorder *aMFR)
{
nsAutoPtr<gfxTextRun> textRun(aFontGroup->MakeTextRun(aText, aLength,
aParams, aFlags));
aParams, aFlags,
aMFR));
if (!textRun) {
return nullptr;
}
@ -842,6 +843,7 @@ public:
mCurrentFramesAllSameTextRun(nullptr),
mContext(aContext),
mLineContainer(aLineContainer),
mMissingFonts(aPresContext->MissingFontRecorder()),
mBidiEnabled(aPresContext->BidiEnabled()),
mSkipIncompleteTextRuns(false),
mWhichTextRun(aWhichTextRun),
@ -971,7 +973,7 @@ public:
aCapitalize, mContext);
}
void Finish() {
void Finish(gfxMissingFontRecorder* aMFR) {
NS_ASSERTION(!(mTextRun->GetFlags() &
(gfxTextRunFactory::TEXT_UNUSED_FLAGS |
nsTextFrameUtils::TEXT_UNUSED_FLAG)),
@ -979,7 +981,7 @@ public:
if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) {
nsTransformedTextRun* transformedTextRun =
static_cast<nsTransformedTextRun*>(mTextRun);
transformedTextRun->FinishSettingProperties(mContext);
transformedTextRun->FinishSettingProperties(mContext, aMFR);
}
// The way nsTransformedTextRun is implemented, its glyph runs aren't
// available until after nsTransformedTextRun::FinishSettingProperties()
@ -1007,6 +1009,7 @@ private:
// The common ancestor of the current frame and the previous leaf frame
// on the line, or null if there was no previous leaf frame.
nsIFrame* mCommonAncestorWithLastFrame;
gfxMissingFontRecorder* mMissingFonts;
// mMaxTextLength is an upper bound on the size of the text in all mapped frames
// The value UINT32_MAX represents overflow; text will be discarded
uint32_t mMaxTextLength;
@ -1506,7 +1509,7 @@ void BuildTextRunsScanner::FlushLineBreaks(gfxTextRun* aTrailingTextRun)
// TODO cause frames associated with the textrun to be reflowed, if they
// aren't being reflowed already!
}
mBreakSinks[i]->Finish();
mBreakSinks[i]->Finish(mMissingFonts);
}
mBreakSinks.Clear();
@ -2138,27 +2141,31 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
if (mDoubleByteText) {
const char16_t* text = static_cast<const char16_t*>(textPtr);
if (transformingFactory) {
textRun = transformingFactory->MakeTextRun(text, transformedLength, &params,
fontGroup, textFlags, styles.Elements());
textRun = transformingFactory->MakeTextRun(text, transformedLength,
&params, fontGroup, textFlags,
styles.Elements(), true);
if (textRun) {
// ownership of the factory has passed to the textrun
transformingFactory.forget();
}
} else {
textRun = MakeTextRun(text, transformedLength, fontGroup, &params, textFlags);
textRun = MakeTextRun(text, transformedLength, fontGroup, &params,
textFlags, mMissingFonts);
}
} else {
const uint8_t* text = static_cast<const uint8_t*>(textPtr);
textFlags |= gfxFontGroup::TEXT_IS_8BIT;
if (transformingFactory) {
textRun = transformingFactory->MakeTextRun(text, transformedLength, &params,
fontGroup, textFlags, styles.Elements());
textRun = transformingFactory->MakeTextRun(text, transformedLength,
&params, fontGroup, textFlags,
styles.Elements(), true);
if (textRun) {
// ownership of the factory has passed to the textrun
transformingFactory.forget();
}
} else {
textRun = MakeTextRun(text, transformedLength, fontGroup, &params, textFlags);
textRun = MakeTextRun(text, transformedLength, fontGroup, &params,
textFlags, mMissingFonts);
}
}
if (!textRun) {

View File

@ -596,7 +596,7 @@ nsCaseTransformTextRunFactory::TransformString(
void
nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
gfxContext* aRefContext)
gfxContext* aRefContext, gfxMissingFontRecorder *aMFR)
{
nsAutoString convertedString;
nsAutoTArray<bool,50> charsToMergeArray;
@ -631,7 +631,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
} else {
cachedChild = fontGroup->MakeTextRun(
convertedString.BeginReading(), convertedString.Length(),
&innerParams, flags);
&innerParams, flags, aMFR);
child = cachedChild.get();
}
if (!child)
@ -643,7 +643,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
canBreakBeforeArray.Elements(), aRefContext);
if (transformedChild) {
transformedChild->FinishSettingProperties(aRefContext);
transformedChild->FinishSettingProperties(aRefContext, aMFR);
}
if (mergeNeeded) {

View File

@ -21,13 +21,17 @@ public:
nsTransformedTextRun* MakeTextRun(const uint8_t* aString, uint32_t aLength,
const gfxFontGroup::Parameters* aParams,
gfxFontGroup* aFontGroup, uint32_t aFlags,
nsStyleContext** aStyles, bool aOwnsFactory = true);
nsStyleContext** aStyles,
bool aOwnsFactory);
nsTransformedTextRun* MakeTextRun(const char16_t* aString, uint32_t aLength,
const gfxFontGroup::Parameters* aParams,
gfxFontGroup* aFontGroup, uint32_t aFlags,
nsStyleContext** aStyles, bool aOwnsFactory = true);
nsStyleContext** aStyles,
bool aOwnsFactory);
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, gfxContext* aRefContext) = 0;
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
gfxContext* aRefContext,
gfxMissingFontRecorder* aMFR) = 0;
};
/**
@ -48,7 +52,9 @@ public:
: mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory),
mAllUppercase(aAllUppercase) {}
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun, gfxContext* aRefContext) MOZ_OVERRIDE;
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
gfxContext* aRefContext,
gfxMissingFontRecorder* aMFR) MOZ_OVERRIDE;
// Perform a transformation on the given string, writing the result into
// aConvertedString. If aAllUppercase is true, the transform is (global)
@ -105,11 +111,12 @@ public:
* are done and before we request any data from the textrun. Also always
* called after a Create.
*/
void FinishSettingProperties(gfxContext* aRefContext)
void FinishSettingProperties(gfxContext* aRefContext,
gfxMissingFontRecorder* aMFR)
{
if (mNeedsRebuild) {
mNeedsRebuild = false;
mFactory->RebuildTextRun(this, aRefContext);
mFactory->RebuildTextRun(this, aRefContext, aMFR);
}
}

View File

@ -389,7 +389,7 @@ nsPropertiesTable::MakeTextRun(gfxContext* aThebesContext,
"nsPropertiesTable can only access glyphs by code point");
return aFontGroup->
MakeTextRun(aGlyph.code, aGlyph.Length(), aThebesContext,
aAppUnitsPerDevPixel, 0);
aAppUnitsPerDevPixel, 0, nullptr);
}
// An instance of nsOpenTypeTable is associated with one gfxFontEntry that
@ -470,7 +470,7 @@ nsOpenTypeTable::UpdateCache(gfxContext* aThebesContext,
if (mCharCache != aChar) {
nsAutoPtr<gfxTextRun> textRun;
textRun = aFontGroup->
MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0);
MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0, nullptr);
const gfxTextRun::CompressedGlyph& data = textRun->GetCharacterGlyphs()[0];
if (data.IsSimpleGlyph()) {
mGlyphID = data.GetSimpleGlyph();
@ -1553,7 +1553,8 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
nsAutoPtr<gfxTextRun> textRun;
textRun = fm->GetThebesFontGroup()->
MakeTextRun(static_cast<const char16_t*>(mData.get()), len, aThebesContext,
aPresContext->AppUnitsPerDevPixel(), 0);
aPresContext->AppUnitsPerDevPixel(), 0,
aPresContext->MissingFontRecorder());
aDesiredStretchSize = MeasureTextRun(aThebesContext, textRun);
mGlyphs[0] = textRun;

View File

@ -592,6 +592,10 @@ pref("gfx.bundled_fonts.enabled", true);
pref("gfx.bundled_fonts.force-enabled", false);
#endif
// Do we fire a notification about missing fonts, so the front-end can decide
// whether to try and do something about it (e.g. download additional fonts)?
pref("gfx.missing_fonts.notify", false);
pref("gfx.filter.nearest.force-enabled", false);
// prefs controlling the font (name/cmap) loader that runs shortly after startup