Bug 387969. Use CSS 'text-rendering' property to control text quality. r=pavlov,r+sr=bzbarsky

This commit is contained in:
roc+@cs.cmu.edu 2007-07-26 02:47:43 -07:00
Родитель d573a81aec
Коммит 377804c1a1
11 изменённых файлов: 131 добавлений и 29 удалений

Просмотреть файл

@ -489,7 +489,13 @@ public:
* When set, optional ligatures are disabled. Ligatures that are
* required for legible text should still be enabled.
*/
TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0400
TEXT_DISABLE_OPTIONAL_LIGATURES = 0x0400,
/**
* When set, the textrun should favour speed of construction over
* quality. This may involve disabling ligatures and/or kerning or
* other effects.
*/
TEXT_OPTIMIZE_SPEED = 0x0800
};
/**

Просмотреть файл

@ -830,6 +830,16 @@ gfxPangoFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
return run;
}
static PRBool
CanTakeFastPath(PRUint32 aFlags)
{
// Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't
// We need to always use Pango for RTL text, in case glyph mirroring is required
return (aFlags &
(gfxTextRunFactory::TEXT_OPTIMIZE_SPEED | gfxTextRunFactory::TEXT_IS_RTL)) ==
gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
}
gfxTextRun *
gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags)
@ -843,14 +853,17 @@ gfxPangoFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
nsCAutoString utf8;
PRInt32 headerLen = AppendDirectionalIndicatorUTF8(run->IsRightToLeft(), utf8);
AppendUTF16toUTF8(Substring(aString, aString + aLength), utf8);
PRUint32 allBits = 0;
PRBool is8Bit = PR_FALSE;
#if defined(ENABLE_XFT_FAST_PATH_8BIT)
PRUint32 i;
for (i = 0; i < aLength; ++i) {
allBits |= aString[i];
if (CanTakeFastPath(aFlags)) {
PRUint32 allBits;
PRUint32 i;
for (i = 0; i < aLength; ++i) {
allBits |= aString[i];
}
is8Bit = (allBits & 0xFF00) == 0;
}
#endif
PRBool is8Bit = (allBits & 0xFF00) == 0;
InitTextRun(run, utf8.get(), utf8.Length(), headerLen, is8Bit);
return run;
}
@ -864,8 +877,7 @@ gfxPangoFontGroup::InitTextRun(gfxTextRun *aTextRun, const gchar *aUTF8Text,
CreateGlyphRunsXft(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength);
#else
#if defined(ENABLE_XFT_FAST_PATH_8BIT)
// We need to always use Pango for RTL text, in case glyph mirroring is required
if (aTake8BitPath && !aTextRun->IsRightToLeft()) {
if (aTake8BitPath && CanTakeFastPath(aTextRun->GetFlags())) {
CreateGlyphRunsXft(aTextRun, aUTF8Text + aUTF8HeaderLength, aUTF8Length - aUTF8HeaderLength);
return;
}

Просмотреть файл

@ -93,6 +93,7 @@ protected:
PRPackedBool mIsDoubleByteText;
PRPackedBool mIsRTL;
PRPackedBool mEnabledOptionalLigatures;
PRPackedBool mOptimizeSpeed;
CacheHashKey(gfxTextRun *aBaseTextRun, void *aFontOrGroup,
PRUint32 aStart, PRUint32 aLength, PRUint32 aHash)
@ -102,7 +103,8 @@ protected:
mStringHash(aHash),
mIsDoubleByteText((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) == 0),
mIsRTL(aBaseTextRun->IsRightToLeft()),
mEnabledOptionalLigatures((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0)
mEnabledOptionalLigatures((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0),
mOptimizeSpeed((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) != 0)
{
}
};
@ -586,7 +588,8 @@ TextRunWordCache::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
GetFontOrGroup(fontGroup, mHashedByFont) != aKey->mFontOrGroup ||
aKey->mAppUnitsPerDevUnit != mTextRun->GetAppUnitsPerDevUnit() ||
aKey->mIsRTL != mTextRun->IsRightToLeft() ||
aKey->mEnabledOptionalLigatures != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0))
aKey->mEnabledOptionalLigatures != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0) ||
aKey->mOptimizeSpeed != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) != 0))
return PR_FALSE;
if (mTextRun->GetFlags() & gfxFontGroup::TEXT_IS_8BIT) {
@ -608,7 +611,8 @@ PLDHashNumber
TextRunWordCache::CacheHashEntry::HashKey(const KeyTypePointer aKey)
{
return aKey->mStringHash + (long)aKey->mFontOrGroup + aKey->mAppUnitsPerDevUnit +
aKey->mIsDoubleByteText + aKey->mIsRTL*2 + aKey->mEnabledOptionalLigatures*4;
aKey->mIsDoubleByteText + aKey->mIsRTL*2 + aKey->mEnabledOptionalLigatures*4 +
aKey->mOptimizeSpeed*8;
}
static TextRunWordCache *gTextRunWordCache = nsnull;

Просмотреть файл

@ -504,6 +504,16 @@ gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
return new gfxWindowsFontGroup(mFamilies, aStyle);
}
static PRBool
CanTakeFastPath(PRUint32 aFlags)
{
// Can take fast path only if OPTIMIZE_SPEED is set and IS_RTL isn't
// We need to always use Uniscribe for RTL text, in case glyph mirroring is required
return (aFlags &
(gfxTextRunFactory::TEXT_OPTIMIZE_SPEED | gfxTextRunFactory::TEXT_IS_RTL)) ==
gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
}
gfxTextRun *
gfxWindowsFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
const Parameters *aParams, PRUint32 aFlags)
@ -522,8 +532,8 @@ gfxWindowsFontGroup::MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
#ifdef FORCE_UNISCRIBE
const PRBool isComplex = PR_TRUE;
#else
const PRBool isComplex = ScriptIsComplex(aString, aLength, SIC_COMPLEX) == S_OK ||
textRun->IsRightToLeft();
const PRBool isComplex = !CanTakeFastPath(aFlags) ||
ScriptIsComplex(aString, aLength, SIC_COMPLEX) == S_OK;
#endif
if (isComplex)
InitTextRunUniscribe(aParams->mContext, textRun, aString, aLength);
@ -547,7 +557,7 @@ gfxWindowsFontGroup::MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
#ifdef FORCE_UNISCRIBE
const PRBool isComplex = PR_TRUE;
#else
const PRBool isComplex = textRun->IsRightToLeft();
const PRBool isComplex = !CanTakeFastPath(aFlags);
#endif
/* We can only call GDI "A" functions if this is a true 7bit ASCII string,

Просмотреть файл

@ -65,9 +65,11 @@
#include "imgIContainer.h"
#include "gfxRect.h"
#include "gfxContext.h"
#include "gfxFont.h"
#include "nsIImage.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsCSSRendering.h"
#include "nsContentUtils.h"
#ifdef MOZ_SVG_FOREIGNOBJECT
#include "nsSVGForeignObjectFrame.h"
@ -2333,3 +2335,38 @@ nsLayoutUtils::FrameHasTransparency(nsIFrame* aFrame) {
return PR_TRUE;
return PR_FALSE;
}
static PRBool
IsNonzeroCoord(const nsStyleCoord& aCoord)
{
if (eStyleUnit_Coord == aCoord.GetUnit())
return aCoord.GetCoordValue() != 0;
return PR_FALSE;
}
/* static */ PRUint32
nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
const nsStyleText* aStyleText,
const nsStyleFont* aStyleFont)
{
PRUint32 result = 0;
if (IsNonzeroCoord(aStyleText->mLetterSpacing)) {
result |= gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES;
}
#ifdef MOZ_SVG
switch (aStyleContext->GetStyleSVG()->mTextRendering) {
case NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED:
result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
break;
case NS_STYLE_TEXT_RENDERING_AUTO:
if (aStyleFont->mFont.size <
aStyleContext->PresContext()->GetAutoQualityMinFontSize()) {
result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
}
break;
default:
break;
}
#endif
return result;
}

Просмотреть файл

@ -700,6 +700,17 @@ public:
* @return a value suitable for passing to SetWindowTranslucency
*/
static PRBool FrameHasTransparency(nsIFrame* aFrame);
/**
* Get textrun construction flags determined by a given style; in particular
* some combination of:
* -- TEXT_DISABLE_OPTIONAL_LIGATURES if letter-spacing is in use
* -- TEXT_OPTIMIZE_SPEED if the text-rendering CSS property and font size
* and prefs indicate we should be optimizing for speed over quality
*/
static PRUint32 GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
const nsStyleText* aStyleText,
const nsStyleFont* aStyleFont);
};
#endif // nsLayoutUtils_h__

Просмотреть файл

@ -669,6 +669,8 @@ nsPresContext::ClearStyleDataAndReflow()
}
}
static const char sMinFontSizePref[] = "browser.display.auto_quality_min_font_size";
void
nsPresContext::PreferenceChanged(const char* aPrefName)
{
@ -687,6 +689,11 @@ nsPresContext::PreferenceChanged(const char* aPrefName)
}
return;
}
if (!nsCRT::strcmp(aPrefName, sMinFontSizePref)) {
mAutoQualityMinFontSizePixelsPref = nsContentUtils::GetIntPref(sMinFontSizePref);
ClearStyleDataAndReflow();
return;
}
// we use a zero-delay timer to coalesce multiple pref updates
if (!mPrefChangedTimer)
{
@ -780,6 +787,9 @@ nsPresContext::Init(nsIDeviceContext* aDeviceContext)
nsPresContext::PrefChangedCallback,
this);
// This is observed thanks to the browser.display. observer above.
mAutoQualityMinFontSizePixelsPref = nsContentUtils::GetIntPref(sMinFontSizePref);
rv = mEventManager->Init();
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -470,6 +470,10 @@ public:
float GetFullZoom() {return mDeviceContext->GetPixelScale();}
void SetFullZoom(float aZoom);
nscoord GetAutoQualityMinFontSize() {
return DevPixelsToAppUnits(mAutoQualityMinFontSizePixelsPref);
}
static PRInt32 AppUnitsPerCSSPixel() { return nsIDeviceContext::AppUnitsPerCSSPixel(); }
PRInt32 AppUnitsPerDevPixel() const { return mDeviceContext->AppUnitsPerDevPixel(); }
PRInt32 AppUnitsPerInch() const { return mDeviceContext->AppUnitsPerInch(); }
@ -755,6 +759,7 @@ protected:
nsWeakPtr mContainer;
float mTextZoom; // Text zoom, defaults to 1.0
PRInt32 mAutoQualityMinFontSizePixelsPref;
#ifdef IBMBIDI
nsBidiPresUtils* mBidiUtils;

Просмотреть файл

@ -1284,12 +1284,6 @@ static nscoord StyleToCoord(const nsStyleCoord& aCoord)
}
}
static PRBool
ShouldDisableOptionalLigatures(const nsStyleText* aTextStyle)
{
return StyleToCoord(aTextStyle->mLetterSpacing) != 0;
}
static PRBool
HasTerminalNewline(const nsTextFrame* aFrame)
{
@ -1320,9 +1314,13 @@ BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1, nsTextFr
nsStyleContext* sc2 = aFrame2->GetStyleContext();
if (sc1 == sc2)
return PR_TRUE;
return sc1->GetStyleFont()->mFont.BaseEquals(sc2->GetStyleFont()->mFont) &&
const nsStyleFont* fontStyle1 = sc1->GetStyleFont();
const nsStyleFont* fontStyle2 = sc2->GetStyleFont();
const nsStyleText* textStyle2 = sc2->GetStyleText();
return fontStyle1->mFont.BaseEquals(fontStyle2->mFont) &&
sc1->GetStyleVisibility()->mLangGroup == sc2->GetStyleVisibility()->mLangGroup &&
ShouldDisableOptionalLigatures(textStyle1) == ShouldDisableOptionalLigatures(sc2->GetStyleText());
nsLayoutUtils::GetTextRunFlagsForStyle(sc1, textStyle1, fontStyle1) ==
nsLayoutUtils::GetTextRunFlagsForStyle(sc2, textStyle2, fontStyle2);
}
void BuildTextRunsScanner::ScanFrame(nsIFrame* aFrame)
@ -1531,14 +1529,18 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
PRUint32 i;
const nsStyleText* textStyle = nsnull;
const nsStyleFont* fontStyle = nsnull;
nsStyleContext* lastStyleContext = nsnull;
for (i = 0; i < mMappedFlows.Length(); ++i) {
MappedFlow* mappedFlow = &mMappedFlows[i];
nsTextFrame* f = mappedFlow->mStartFrame;
mappedFlow->mTransformedTextOffset = currentTransformedTextOffset;
lastStyleContext = f->GetStyleContext();
// Detect use of text-transform or font-variant anywhere in the run
const nsStyleText* textStyle = f->GetStyleText();
textStyle = f->GetStyleText();
if (NS_STYLE_TEXT_TRANSFORM_NONE != textStyle->mTextTransform) {
anyTextTransformStyle = PR_TRUE;
}
@ -1548,7 +1550,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
if (NS_STYLE_TEXT_ALIGN_JUSTIFY == textStyle->mTextAlign && compressWhitespace) {
textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING;
}
const nsStyleFont* fontStyle = f->GetStyleFont();
fontStyle = f->GetStyleFont();
if (NS_STYLE_FONT_VARIANT_SMALL_CAPS == fontStyle->mFont.variant) {
anySmallcapsStyle = PR_TRUE;
}
@ -1708,10 +1710,11 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
if (mTrimNextRunLeadingWhitespace) {
textFlags |= nsTextFrameUtils::TEXT_TRAILING_WHITESPACE;
}
if (ShouldDisableOptionalLigatures(firstFrame->GetStyleText())) {
textFlags |= gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES;
}
// ContinueTextRunAcrossFrames guarantees that it doesn't matter which
// frame's style is used, so use the last frame's
textFlags |= nsLayoutUtils::GetTextRunFlagsForStyle(lastStyleContext,
textStyle, fontStyle);
gfxSkipChars skipChars;
skipChars.TakeFrom(&builder);
// Convert linebreak coordinates to transformed string offsets

Просмотреть файл

@ -1351,8 +1351,10 @@ nsSVGGlyphFrame::GetTextRun(gfxContext *aCtx, const nsString &aText)
if (!mFontGroup)
return nsnull;
PRUint32 flags = nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(),
GetStyleText(), GetStyleFont());
return gfxTextRunCache::MakeTextRun(aText.get(), aText.Length(),
mFontGroup, aCtx, 1, 0);
mFontGroup, aCtx, 1, flags);
}
//----------------------------------------------------------------------

Просмотреть файл

@ -86,6 +86,8 @@ pref("browser.display.force_inline_alttext", false); // true = force ALT text fo
// 2 = add extra leading both internal leading and external leading are zero
pref("browser.display.normal_lineheight_calc_control", 2);
pref("browser.display.show_image_placeholders", true); // true = show image placeholders while image is loaded and when image is broken
// min font device pixel size at which to turn on high quality
pref("browser.display.auto_quality_min_font_size", 60);
pref("browser.anchor_color", "#0000EE");
pref("browser.active_color", "#EE0000");
pref("browser.visited_color", "#551A8B");