Bug 333659. (Re)landing gfx changes: new gfxTextRun interfaces, implementation of gfxPangoTextRun, stub implementations for Mac and Windows, nsThebesRenderingContext reimplemented on top of the new interfaces. r=pavlov

This commit is contained in:
roc+%cs.cmu.edu 2007-01-23 08:45:52 +00:00
Родитель 326c234dbe
Коммит fa82daaaaf
18 изменённых файлов: 3165 добавлений и 670 удалений

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

@ -124,7 +124,7 @@ CPPSRCS += nsSystemFontsMac.cpp
endif
endif
EXPORTS += nsIThebesRenderingContext.h
EXPORTS += nsIThebesRenderingContext.h nsIThebesFontMetrics.h
LOCAL_INCLUDES = \
-I$(srcdir)/. \

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

@ -43,6 +43,8 @@
class nsThebesRenderingContext;
class gfxFontGroup;
class nsIThebesFontMetrics : public nsIFontMetrics {
public:
// Get the width for this string. aWidth will be updated with the
@ -108,8 +110,11 @@ public:
// Set the direction of the text rendering
virtual nsresult SetRightToLeftText(PRBool aIsRTL) = 0;
virtual PRBool GetRightToLeftText() = 0;
virtual void SetTextRunRTL(PRBool aIsRTL) = 0;
virtual PRInt32 GetMaxStringLength() = 0;
virtual gfxFontGroup* GetThebesFontGroup() = 0;
};
#endif /* __nsIThebesFontMetrics_h */

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

@ -40,9 +40,10 @@
#include "nsFont.h"
#include "nsString.h"
#include "nsAutoBuffer.h"
#include <stdio.h>
#include "gfxTextRunCache.h"
NS_IMPL_ISUPPORTS1(nsThebesFontMetrics, nsIFontMetrics)
#include <stdlib.h>
@ -55,8 +56,6 @@ NS_IMPL_ISUPPORTS1(nsThebesFontMetrics, nsIFontMetrics)
#include "gfxAtsuiFonts.h"
#endif
#include "gfxTextRunCache.h"
nsThebesFontMetrics::nsThebesFontMetrics()
{
mFontStyle = nsnull;
@ -77,7 +76,8 @@ nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup,
mLangGroup = aLangGroup;
mDeviceContext = (nsThebesDeviceContext*)aContext;
mDev2App = aContext->DevUnitsToAppUnits();
mIsRTL = PR_FALSE;
mIsRightToLeft = PR_FALSE;
mTextRunRTL = PR_FALSE;
// work around layout giving us 0 sized fonts...
double size = aFont.size * mDeviceContext->AppUnitsToDevUnits();
@ -283,6 +283,43 @@ nsThebesFontMetrics::GetMaxStringLength()
return PR_MAX(1, len);
}
class StubPropertyProvider : public gfxTextRun::PropertyProvider {
public:
StubPropertyProvider(const nscoord* aSpacing = nsnull)
: mSpacing(aSpacing) {}
virtual void ForceRememberText() {
NS_ERROR("This shouldn't be called because we already asked the textrun to remember");
}
virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore) {
NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText");
}
virtual gfxFloat GetHyphenWidth() {
NS_ERROR("This shouldn't be called because we never specify hyphen breaks");
return 0;
}
virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength,
Spacing* aSpacing);
private:
const nscoord* mSpacing;
};
void
StubPropertyProvider::GetSpacing(PRUint32 aStart, PRUint32 aLength,
Spacing* aSpacing)
{
PRUint32 i;
for (i = 0; i < aLength; ++i) {
aSpacing[i].mBefore = 0;
// mSpacing is absolute (already includes the character width). This is OK
// because gfxTextRunCache sets TEXT_ABSOLUTE_SPACING when it creates
// the textrun.
aSpacing[i].mAfter = mSpacing ? mSpacing[aStart + i] : 0;
}
}
nsresult
nsThebesFontMetrics::GetWidth(const char* aString, PRUint32 aLength, nscoord& aWidth,
nsThebesRenderingContext *aContext)
@ -296,13 +333,12 @@ nsThebesFontMetrics::GetWidth(const char* aString, PRUint32 aLength, nscoord& aW
if ((aLength == 1) && (aString[0] == ' '))
return GetSpaceWidth(aWidth);
const nsDependentCSubstring& theString = nsDependentCSubstring(aString, aString+aLength);
//nsRefPtr<gfxTextRun> textrun = mFontGroup->MakeTextRun(theString);
nsRefPtr<gfxTextRun> textrun = gfxTextRunCache::GetCache()->GetOrMakeTextRun(mFontGroup, theString);
StubPropertyProvider provider;
AutoTextRun textRun(this, aContext, aString, aLength, PR_FALSE);
if (!textRun.get())
return NS_ERROR_FAILURE;
textrun->SetRightToLeft(mIsRTL);
aWidth = ROUND_TO_TWIPS(textrun->Measure(aContext->Thebes()));
aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
return NS_OK;
}
@ -321,16 +357,14 @@ nsThebesFontMetrics::GetWidth(const PRUnichar* aString, PRUint32 aLength,
if ((aLength == 1) && (aString[0] == ' '))
return GetSpaceWidth(aWidth);
const nsDependentSubstring& theString = nsDependentSubstring(aString, aString+aLength);
//nsRefPtr<gfxTextRun> textrun = mFontGroup->MakeTextRun(theString);
nsRefPtr<gfxTextRun> textrun = gfxTextRunCache::GetCache()->GetOrMakeTextRun(mFontGroup, theString);
StubPropertyProvider provider;
AutoTextRun textRun(this, aContext, aString, aLength, PR_FALSE);
if (!textRun.get())
return NS_ERROR_FAILURE;
textrun->SetRightToLeft(mIsRTL);
aWidth = ROUND_TO_TWIPS(textrun->Measure(aContext->Thebes()));
aWidth = NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider));
return NS_OK;
}
// Get the text dimensions for this string
@ -380,68 +414,47 @@ nsThebesFontMetrics::DrawString(const char *aString, PRUint32 aLength,
if (aLength == 0)
return NS_OK;
float app2dev = mDeviceContext->AppUnitsToDevUnits();
const nsDependentCSubstring& theString = nsDependentCSubstring(aString, aString+aLength);
//nsRefPtr<gfxTextRun> textrun = mFontGroup->MakeTextRun(theString);
nsRefPtr<gfxTextRun> textrun = gfxTextRunCache::GetCache()->GetOrMakeTextRun(mFontGroup, theString);
textrun->SetRightToLeft(mIsRTL);
if (aSpacing) {
gfxFloat offset = aX * app2dev;
nsTArray<gfxFloat> spacing(aLength);
for (PRUint32 i = 0; i < aLength; ++i) {
gfxFloat nextOffset = offset + aSpacing[i] * app2dev;
spacing.AppendElement(NSToIntRound(nextOffset) -
NSToIntRound(offset));
offset = nextOffset;
}
textrun->SetSpacing(spacing);
StubPropertyProvider provider(aSpacing);
AutoTextRun textRun(this, aContext, aString, aLength, aSpacing != nsnull);
if (!textRun.get())
return NS_ERROR_FAILURE;
gfxPoint pt(aX, aY);
#ifdef MOZ_X11
if (mTextRunRTL) {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
}
aContext->Thebes()->DrawTextRun(textrun, gfxPoint(NSToIntRound(aX * app2dev), NSToIntRound(aY * app2dev)));
#endif
textRun->Draw(aContext->Thebes(), pt, 0, aLength,
nsnull, &provider, nsnull);
return NS_OK;
}
// aCachedOffset will be updated with a new offset.
nsresult
nsThebesFontMetrics::DrawString(const PRUnichar* aString, PRUint32 aLength,
nscoord aX, nscoord aY,
PRInt32 aFontID,
const nscoord* aSpacing,
nsThebesRenderingContext *aContext)
nscoord aX, nscoord aY,
PRInt32 aFontID,
const nscoord* aSpacing,
nsThebesRenderingContext *aContext)
{
if (aLength == 0)
return NS_OK;
float app2dev = mDeviceContext->AppUnitsToDevUnits();
const nsDependentSubstring& theString = nsDependentSubstring(aString, aString+aLength);
//nsRefPtr<gfxTextRun> textrun = mFontGroup->MakeTextRun(theString);
nsRefPtr<gfxTextRun> textrun = gfxTextRunCache::GetCache()->GetOrMakeTextRun(mFontGroup, theString);
textrun->SetRightToLeft(mIsRTL);
if (aSpacing) {
gfxFloat offset = aX * app2dev;
nsTArray<gfxFloat> spacing(aLength);
for (PRUint32 i = 0; i < aLength; ++i) {
gfxFloat nextOffset = offset + aSpacing[i] * app2dev;
spacing.AppendElement(NSToIntRound(nextOffset) -
NSToIntRound(offset));
offset = nextOffset;
}
textrun->SetSpacing(spacing);
StubPropertyProvider provider(aSpacing);
AutoTextRun textRun(this, aContext, aString, aLength, aSpacing != nsnull);
if (!textRun.get())
return NS_ERROR_FAILURE;
gfxPoint pt(aX, aY);
#ifdef MOZ_X11
if (mTextRunRTL) {
pt.x += textRun->GetAdvanceWidth(0, aLength, &provider);
}
aContext->Thebes()->DrawTextRun(textrun, gfxPoint(NSToIntRound(aX * app2dev), NSToIntRound(aY * app2dev)));
#endif
textRun->Draw(aContext->Thebes(), pt, 0, aLength,
nsnull, &provider, nsnull);
return NS_OK;
}
#ifdef MOZ_MATHML
// These two functions get the bounding metrics for this handle,
// updating the aBoundingMetrics in Points. This means that the
@ -470,7 +483,7 @@ nsThebesFontMetrics::GetBoundingMetrics(const PRUnichar *aString,
nsresult
nsThebesFontMetrics::SetRightToLeftText(PRBool aIsRTL)
{
mIsRTL = aIsRTL;
mIsRightToLeft = aIsRTL;
return NS_OK;
}
@ -478,5 +491,5 @@ nsThebesFontMetrics::SetRightToLeftText(PRBool aIsRTL)
PRBool
nsThebesFontMetrics::GetRightToLeftText()
{
return mIsRTL;
return mIsRightToLeft;
}

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

@ -46,6 +46,7 @@
#include "nsIAtom.h"
#include "gfxFont.h"
#include "gfxTextRunCache.h"
class nsThebesFontMetrics : public nsIThebesFontMetrics
{
@ -142,11 +143,51 @@ public:
// Set the direction of the text rendering
virtual nsresult SetRightToLeftText(PRBool aIsRTL);
virtual PRBool GetRightToLeftText();
virtual void SetTextRunRTL(PRBool aIsRTL) { mTextRunRTL = aIsRTL; }
virtual gfxFontGroup* GetThebesFontGroup() { return mFontGroup; }
PRBool GetRightToLeftTextRunMode() {
#ifdef MOZ_X11
return mTextRunRTL;
#else
return mIsRightToLeft;
#endif
}
protected:
const gfxFont::Metrics& GetMetrics() const;
class AutoTextRun {
public:
AutoTextRun(nsThebesFontMetrics* aMetrics, nsIRenderingContext* aRC,
const char* aString, PRInt32 aLength, PRBool aEnableSpacing) {
mTextRun = gfxTextRunCache::GetCache()->GetOrMakeTextRun(
NS_STATIC_CAST(gfxContext*, aRC->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT)),
aMetrics->mFontGroup, aString, aLength, aMetrics->mDev2App,
aMetrics->GetRightToLeftTextRunMode(), aEnableSpacing, &mOwning);
}
AutoTextRun(nsThebesFontMetrics* aMetrics, nsIRenderingContext* aRC,
const PRUnichar* aString, PRInt32 aLength, PRBool aEnableSpacing) {
mTextRun = gfxTextRunCache::GetCache()->GetOrMakeTextRun(
NS_STATIC_CAST(gfxContext*, aRC->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT)),
aMetrics->mFontGroup, aString, aLength, aMetrics->mDev2App,
aMetrics->GetRightToLeftTextRunMode(), aEnableSpacing, &mOwning);
}
~AutoTextRun() {
if (mOwning) {
delete mTextRun;
}
}
gfxTextRun* operator->() { return mTextRun; }
gfxTextRun* get() { return mTextRun; }
private:
gfxTextRun* mTextRun;
PRBool mOwning;
};
friend class AutoTextRun;
nsRefPtr<gfxFontGroup> mFontGroup;
gfxFontStyle *mFontStyle;
@ -154,7 +195,8 @@ private:
nsThebesDeviceContext *mDeviceContext;
nsCOMPtr<nsIAtom> mLangGroup;
float mDev2App;
PRBool mIsRTL;
PRPackedBool mIsRightToLeft;
PRPackedBool mTextRunRTL;
};
#endif /* NSTHEBESFONTMETRICS__H__ */

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

@ -1104,6 +1104,12 @@ nsThebesRenderingContext::GetRightToLeftText(PRBool* aIsRTL)
return NS_OK;
}
void
nsThebesRenderingContext::SetTextRunRTL(PRBool aIsRTL)
{
mFontMetrics->SetTextRunRTL(aIsRTL);
}
NS_IMETHODIMP
nsThebesRenderingContext::SetFont(const nsFont& aFont, nsIAtom* aLangGroup)
{

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

@ -242,6 +242,7 @@ public:
const nsRect * aTargetRect);
NS_IMETHOD SetRightToLeftText(PRBool aIsRTL);
NS_IMETHOD GetRightToLeftText(PRBool* aIsRTL);
virtual void SetTextRunRTL(PRBool aIsRTL);
NS_IMETHOD GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,

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

@ -11,7 +11,7 @@ MODULE = thebes
DIRS = public src
ifdef ENABLE_TESTS
TOOL_DIRS += test
# TOOL_DIRS += test
endif
include $(topsrcdir)/config/rules.mk

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

@ -86,10 +86,14 @@ public:
const gfxFontStyle *aStyle);
virtual ~gfxAtsuiFontGroup();
virtual gfxTextRun *MakeTextRun(const nsAString& aString);
virtual gfxTextRun *MakeTextRun(const nsACString& aCString) {
return MakeTextRun(NS_ConvertASCIItoUTF16(aCString));
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) {
NS_ERROR("NOT IMPLEMENTED");
return nsnull;
}
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams);
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams);
ATSUFontFallbacks *GetATSUFontFallbacksPtr() { return &mFallbacks; }
@ -107,7 +111,7 @@ protected:
ATSUFontFallbacks mFallbacks;
};
class THEBES_API gfxAtsuiTextRun : public gfxTextRun {
class THEBES_API gfxAtsuiTextRun {
public:
gfxAtsuiTextRun(const nsAString& aString, gfxAtsuiFontGroup *aFontGroup);
~gfxAtsuiTextRun();
@ -118,6 +122,9 @@ public:
virtual void SetSpacing(const nsTArray<gfxFloat>& spacingArray);
virtual const nsTArray<gfxFloat> *const GetSpacing() const;
void SetRightToLeft(PRBool aIsRTL) { mIsRTL = aIsRTL; }
PRBool IsRightToLeft() { return mIsRTL; }
private:
nsString mString;
gfxAtsuiFontGroup *mGroup;
@ -125,6 +132,8 @@ private:
ATSUTextLayout mATSULayout;
nsTArray<ATSUStyle> mStylesToDispose;
PRPackedBool mIsRTL;
};
#endif /* GFX_ATSUIFONTS_H */

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

@ -51,7 +51,6 @@
#include "gfxFont.h"
class gfxRegion;
class gfxTextRun;
/**
* This is the main class for doing actual drawing. It is initialized using
@ -191,22 +190,6 @@ public:
void Ellipse(gfxPoint center, gfxSize dimensions);
void Polygon(const gfxPoint *points, PRUint32 numPoints);
/**
** Text
**/
/**
* Add the text outline to the current path.
*/
// specify this in a sane way.
//void AddStringToPath(gfxTextRun& text);
/**
* Draw the text run at the current point.
* XXX support drawing subsections of the text run
*/
void DrawTextRun(gfxTextRun *text, gfxPoint pt);
/**
** Transformation Matrix manipulation
**/

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

@ -44,9 +44,12 @@
#include "nsString.h"
#include "gfxPoint.h"
#include "nsTArray.h"
#include "gfxSkipChars.h"
#include "gfxRect.h"
class gfxContext;
class gfxTextRun;
class nsIAtom;
#define FONT_STYLE_NORMAL 0
#define FONT_STYLE_ITALIC 1
@ -149,6 +152,7 @@ public:
gfxFloat strikeoutOffset;
gfxFloat underlineSize;
gfxFloat underlineOffset;
gfxFloat height;
gfxFloat internalLeading;
gfxFloat externalLeading;
@ -173,10 +177,94 @@ protected:
const gfxFontStyle *mStyle;
};
class THEBES_API gfxTextRunFactory {
THEBES_INLINE_DECL_REFCOUNTING(gfxTextRunFactory)
class THEBES_API gfxFontGroup {
THEBES_INLINE_DECL_REFCOUNTING(gfxFontGroup)
public:
// Flags >= 0x10000 are reserved for textrun clients
enum {
/**
* When set, the text string pointer used to create the text run
* is guaranteed to be available during the lifetime of the text run.
*/
TEXT_IS_PERSISTENT = 0x0001,
/**
* When set, the text is known to be all-ASCII (< 128).
*/
TEXT_IS_ASCII = 0x0002,
/**
* When set, the text is RTL.
*/
TEXT_IS_RTL = 0x0004,
/**
* When set, spacing is enabled and the textrun needs to call GetSpacing
* on the spacing provider.
*/
TEXT_ENABLE_SPACING = 0x0008,
/**
* When set, GetSpacing can return negative spacing.
*/
TEXT_ENABLE_NEGATIVE_SPACING = 0x0010,
/**
* When set, mAfter spacing for a character already includes the character
* width. Otherwise, it does not include the character width.
*/
TEXT_ABSOLUTE_SPACING = 0x0020,
/**
* When set, GetHyphenationBreaks may return true for some character
* positions, otherwise it will always return false for all characters.
*/
TEXT_ENABLE_HYPHEN_BREAKS = 0x0040,
/**
* When set, the text has no characters above 255.
*/
TEXT_IS_8BIT = 0x0080,
/**
* When set, the text may have UTF16 surrogate pairs, otherwise it
* doesn't.
*/
TEXT_HAS_SURROGATES = 0x0100
};
/**
* This record contains all the parameters needed to initialize a textrun.
*/
struct Parameters {
// A reference context suggesting where the textrun will be rendered
gfxContext* mContext;
// Pointer to arbitrary user data (which should outlive the textrun)
void* mUserData;
// The language of the text, or null if not known
nsIAtom* mLangGroup;
// A description of which characters have been stripped from the original
// DOM string to produce the characters in the textrun
gfxSkipChars* mSkipChars;
// A list of where linebreaks are currently placed in the textrun
PRUint32* mInitialBreaks;
PRUint32 mInitialBreakCount;
// The ratio to use to convert device pixels to application layout units
gfxFloat mPixelsToUnits;
// Flags --- see above
PRUint32 mFlags;
};
virtual ~gfxTextRunFactory() {}
/**
* Create a gfxTextRun from Unicode text. The length is obtained from
* aParams->mSkipChars->GetCharCount().
*/
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams) = 0;
/**
* Create a gfxTextRun from 8-bit Unicode (UCS1?) text. The length is
* obtained from aParams->mSkipChars->GetCharCount().
*/
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams) = 0;
};
class THEBES_API gfxFontGroup : public gfxTextRunFactory {
public:
gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle);
@ -198,10 +286,14 @@ public:
const gfxFontStyle *GetStyle() const { return &mStyle; }
/* unicode method */
virtual gfxTextRun *MakeTextRun(const nsAString& aString) = 0;
/* ASCII text only, not UTF-8 */
virtual gfxTextRun *MakeTextRun(const nsACString& aString) = 0;
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) = 0;
// These need to be repeated from gfxTextRunFactory because of C++'s
// hiding rules!
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams) = 0;
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams) = 0;
/* helper function for splitting font families on commas and
* calling a function for each family to fill the mFonts array
@ -234,27 +326,399 @@ protected:
static PRBool FontResolverProc(const nsAString& aName, void *aClosure);
};
// these do not copy the text
class THEBES_API gfxTextRun {
THEBES_INLINE_DECL_REFCOUNTING(gfxTextRun)
/**
* gfxTextRun is an abstraction for drawing and measuring substrings of a run
* of text.
*
* \r and \n characters must be ignored completely. Substring operations
* will not normally include these characters.
*
* 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; cached spacing is flushed via
* FlushSpacingCache(). 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.)
*
* gfxTextRuns don't need to remember their text ... often it's enough just to
* convert text to glyphs and store glyphs plus some geometry data in packed
* form. However sometimes gfxTextRuns will want to get the original text back
* to handle some unusual situation. So gfxTextRuns have two modes: "not
* remembering text" (initial state) and "remembering text". A call to
* gfxTextRun::RememberText forces a transition from the former to latter state.
* The text is never forgotten. A gfxTextRun call that receives a TextProvider
* object may call ForceRememberText to request a transition to "remembering text".
*
* It is important that zero-length substrings are handled correctly. This will
* be on the test!
*/
class THEBES_API gfxTextRun {
public:
gfxTextRun() : mIsRTL(PR_FALSE) { }
virtual ~gfxTextRun() {}
virtual void Draw(gfxContext *aContext, gfxPoint pt) = 0;
// returns length in pixels
virtual gfxFloat Measure(gfxContext *aContext) = 0;
enum {
// character is the start of a grapheme cluster
CLUSTER_START = 0x01,
// character is a cluster start but is part of a ligature started
// in a previous cluster.
CONTINUES_LIGATURE = 0x02,
// line break opportunity before this character
LINE_BREAK_BEFORE = 0x04
};
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8* aFlags) = 0;
virtual PRUint8 GetCharFlags(PRUint32 aStart) = 0;
virtual void SetSpacing(const nsTArray<gfxFloat> &spacing) = 0;
virtual const nsTArray<gfxFloat> *const GetSpacing() const = 0;
virtual PRUint32 GetLength() = 0;
// defaults to FALSE
virtual void SetRightToLeft(PRBool aIsRTL) { mIsRTL = aIsRTL; }
virtual PRBool IsRightToLeft() const { return mIsRTL; }
// All PRUint32 aStart, PRUint32 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
private:
PRBool mIsRTL;
/**
* This can be called to force gfxTextRun to remember the text used
* to create it and *never* call TextProvider::GetText again.
*
* The default implementation is to not remember anything. If you want
* to be able to recover text from the gfxTextRun user you need to override
* these.
*/
virtual void RememberText(const PRUnichar* aText, PRUint32 aLength) {}
virtual void RememberText(const PRUint8* aText, PRUint32 aLength) {}
/**
* Set the potential linebreaks for a substring of the textrun. These are
* the "allow break before" points. Initially, there are no potential
* linebreaks.
*
* @return true if this changed the linebreaks, false if the new line
* breaks are the same as the old
*/
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore) = 0;
/**
* This is provided so a textrun can (re)obtain the original text used to
* construct it, if necessary.
*/
class TextProvider {
public:
/**
* Recover the text originally used to build the textrun. This should
* only be requested infrequently as it may be slow. If you need to
* call it a lot you should probably be saving the text in the text run
* itself. It just forces the textrun user to call RememberText on the
* text run. If you call this and RememberText doesn't get called,
* then something has failed and you should handle it.
*/
virtual void ForceRememberText() = 0;
};
/**
* 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 TextProvider {
public:
// Detect hyphenation break opportunities in the given range; breaks
// not at cluster boundaries will be ignored.
virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore) = 0;
// Returns the extra width that will be consumed by a hyphen. This should
// be constant for a given textrun.
virtual gfxFloat GetHyphenWidth() = 0;
/**
* We let the property provider specify spacing on either side of any
* character. We need to specify both before and after
* spacing so that substring measurement can do the right things.
*/
struct Spacing {
gfxFloat mBefore;
gfxFloat mAfter;
};
/**
* 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(PRUint32 aStart, PRUint32 aLength,
Spacing* aSpacing) = 0;
};
/**
* 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 aDirtyRect if non-null, drawing outside of the rectangle can be
* (but does not need to be) dropped. Note that if this is null, we cannot
* draw partial ligatures and we will assert if partial ligatures
* are detected.
* @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, nsnull) should have the same effect as
* Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nsnull).
* 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, nsnull) should have the same effect as
* Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nsnull).
*
* Glyphs should be drawn in logical content order, which can be significant
* if they overlap (perhaps due to negative spacing).
*/
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aProvider,
gfxFloat* aAdvanceWidth) = 0;
/**
* Renders a substring to a path. 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 way that Draw above does.
*
* Glyphs should be drawn in logical content order.
*
* UNLIKE Draw above, this cannot be used to render substrings that start or
* end inside a ligature.
*/
virtual void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth) = 0;
/**
* Special strings are strings that we might need to draw/measure but aren't
* actually substrings of the given text. They never have extra spacing and
* aren't involved in breaking.
*/
enum SpecialString {
STRING_ELLIPSIS,
STRING_HYPHEN,
STRING_SPACE,
STRING_MAX = STRING_SPACE
};
/**
* Draw special string.
* The provided point is the baseline origin on the left of the string
* for LTR, on the right of the string for RTL.
*/
virtual void DrawSpecialString(gfxContext *aContext, gfxPoint aPt,
SpecialString aString) = 0;
// Metrics needed by reflow
struct Metrics {
Metrics() {
mAdvanceWidth = mAscent = mDescent = 0.0;
mBoundingBox = gfxRect(0,0,0,0);
mClusterCount = 0;
}
void CombineWith(const Metrics& aOtherOnRight) {
mAscent = PR_MAX(mAscent, aOtherOnRight.mAscent);
mDescent = PR_MAX(mDescent, aOtherOnRight.mDescent);
mBoundingBox =
mBoundingBox.Union(aOtherOnRight.mBoundingBox + gfxPoint(mAdvanceWidth, 0));
mAdvanceWidth += aOtherOnRight.mAdvanceWidth;
mClusterCount += aOtherOnRight.mClusterCount;
}
// can be negative (partly due to negative spacing).
// Advance widths should be additive: the advance width of the
// (offset1, length1) plus the advance width of (offset1 + length1,
// length2) should be the advance width of (offset1, length1 + length2)
gfxFloat mAdvanceWidth;
// For zero-width substrings, these must be zero!
gfxFloat mAscent; // always non-negative
gfxFloat mDescent; // always non-negative
// Bounding box that is guaranteed to include everything drawn.
// If aTightBoundingBox was set to true when these metrics were
// generated, this will tightly wrap the glyphs, otherwise it is
// "loose" and may be larger than the true bounding box.
// Coordinates are relative to the baseline left origin, so typically
// mBoundingBox.y == -mAscent
gfxRect mBoundingBox;
// Count of the number of grapheme clusters. Layout needs
// this to compute tab offsets. For SpecialStrings, this is always 1.
PRInt32 mClusterCount;
};
/**
* Computes the ReflowMetrics for a substring.
* Uses GetSpacing from aBreakProvider.
* @param aTightBoundingBox if true, we make the bounding box tight
*/
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider* aProvider) = 0;
/**
* Computes the ReflowMetrics for a special string.
* Uses GetSpacing from aBreakProvider.
* @param aTightBoundingBox if true, we make the bounding box tight
*/
virtual Metrics MeasureTextSpecialString(SpecialString aString,
PRBool aTightBoundingBox) = 0;
/**
* Computes just the advance width for a substring.
* Uses GetSpacing from aBreakProvider.
*/
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aProvider) = 0;
/**
* Computes the advance width for a special string.
*/
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString) = 0;
/**
* Get the font metrics that we should use for drawing text decorations.
* Overriden here so that transforming gfxTextRuns such as smallcaps
* can do something special if they want to.
*/
virtual gfxFont::Metrics GetDecorationMetrics() = 0;
/**
* 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...)
*
* @param aAdvanceWidthDelta if non-null, returns the change in advance
* width of the given range.
*/
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider* aProvider,
gfxFloat* aAdvanceWidthDelta) = 0;
/**
* 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 PR_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 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 aTightBoundingBox if true, we make the bounding box in aMetrics tight
* @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 PR_UINT32_MAX if no such N exists, where GetAdvanceWidth assumes
* the effect of
* SetLineBreaks(aStart, N, aLineBreakBefore, N < aMaxLength, aProvider)
*
* Note that negative advance widths are possible especially if negative
* spacing is provided.
*/
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider* aProvider,
PRBool aSuppressInitialBreak,
Metrics* aMetrics, PRBool aTightBoundingBox,
PRBool* aUsedHyphenation,
PRUint32* aLastBreak) = 0;
/**
* Update the reference context.
* XXX this is a hack. New text frame does not call this. Use only
* temporarily for old text frame.
*/
virtual void SetContext(gfxContext* aContext) {}
/**
* Flush cached spacing data for the characters at and after aStart.
*/
virtual void FlushSpacingCache(PRUint32 aStart) = 0;
// Utility getters
PRBool IsRightToLeft() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) != 0; }
gfxFloat GetDirection() const { return (mFlags & gfxTextRunFactory::TEXT_IS_RTL) ? -1.0 : 1.0; }
void* GetUserData() const { return mUserData; }
PRUint32 GetFlags() const { return mFlags; }
const gfxSkipChars& GetSkipChars() const { return mSkipChars; }
gfxFloat GetPixelsToAppUnits() { return mPixelsToAppUnits; }
protected:
gfxTextRun(gfxTextRunFactory::Parameters* aParams, PRBool aIs8Bit)
: mUserData(aParams->mUserData), mPixelsToAppUnits(aParams->mPixelsToUnits),
mFlags(aParams->mFlags)
{
mSkipChars.TakeFrom(aParams->mSkipChars);
if (aIs8Bit) {
mFlags |= gfxTextRunFactory::TEXT_IS_8BIT;
}
}
void* mUserData;
gfxSkipChars mSkipChars;
gfxFloat mPixelsToAppUnits;
PRUint32 mFlags;
};
#endif

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

@ -45,8 +45,12 @@
#include <pango/pango.h>
#include <X11/Xft/Xft.h>
//#define USE_XFT_FOR_ASCII
#include "nsDataHashtable.h"
class FontSelector;
class gfxPangoFont : public gfxFont {
public:
gfxPangoFont (const nsAString& aName,
@ -86,8 +90,12 @@ public:
const gfxFontStyle *aStyle);
virtual ~gfxPangoFontGroup ();
virtual gfxTextRun *MakeTextRun(const nsAString& aString);
virtual gfxTextRun *MakeTextRun(const nsACString& aCString);
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams);
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams);
gfxPangoFont *GetFontAt(PRInt32 i) {
return NS_STATIC_CAST(gfxPangoFont*,
@ -104,72 +112,355 @@ public:
void PutCachedFont(const nsAString& aName, gfxPangoFont *aFont) {
mFontCache.Put(aName, aFont);
}
struct SpecialStringData {
PangoGlyphString* mGlyphs;
gfxFloat mAdvance;
SpecialStringData() { mGlyphs = nsnull; }
~SpecialStringData() { if (mGlyphs) pango_glyph_string_free(mGlyphs); }
};
SpecialStringData mSpecialStrings[gfxTextRun::STRING_MAX + 1];
protected:
static PRBool FontCallback (const nsAString& fontName,
const nsACString& genericName,
void *closure);
private:
nsDataHashtable<nsStringHashKey, nsRefPtr<gfxPangoFont> > mFontCache;
nsTArray<gfxFontStyle> mAdditionalStyles;
};
#ifdef USE_XFT_FOR_ASCII
class THEBES_API gfxXftTextRun : public gfxTextRun {
public:
gfxXftTextRun(const nsAString& aString, gfxPangoFontGroup *aFontGroup);
gfxXftTextRun(const nsACString& aString, gfxPangoFontGroup *aFontGroup);
gfxXftTextRun(gfxPangoFontGroup *aGroup,
const char* aString, PRInt32 aLength, PRUint32 aFlags);
~gfxXftTextRun();
virtual void Draw(gfxContext *aContext, gfxPoint pt);
virtual gfxFloat Measure(gfxContext *aContext);
virtual void SetSpacing(const nsTArray<gfxFloat>& spacingArray);
virtual const nsTArray<gfxFloat> *const GetSpacing() const;
virtual nsresult Init(PRBool aIsRTL, nsIAtom* aLangGroup,
gfxFloat aPixelsToUnits,
gfxSkipChars* aSkipChars, void* aUserData);
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8* aFlags);
virtual PRUint8 GetCharFlag(PRUint32 aOffset);
virtual void Draw(gfxContext* aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth);
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
SpecialString aString);
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider* aBreakProvider);
virtual Metrics MeasureText(SpecialString aString,
PRBool aTightBoundingBox);
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider);
virtual gfxFloat GetAdvanceWidth(SpecialString aString);
virtual gfxFont::Metrics& GetDecorationMetrics();
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
gfxFloat aWidth,
PropertyProvider* aBreakProvider,
PRBool aSuppressInitialBreak,
Metrics* aMetrics, PRBool aTightBoundingBox,
PRBool* aUsedHyphenation,
PRUint32* aLastBreak);
virtual void FlushSpacingCache(PRUint32 aStart, PRUint32 aLength);
private:
nsString mWString;
nsCString mCString;
PRBool mIsWide;
gfxPangoFontGroup *mGroup;
int mWidth, mHeight;
nsTArray<gfxFloat> mSpacing;
nsTArray<PRInt32> mUTF8Spacing;
};
#endif
struct TextSegment;
class THEBES_API gfxPangoTextRun : public gfxTextRun {
public:
gfxPangoTextRun(const nsAString& aString, gfxPangoFontGroup *aFontGroup);
gfxPangoTextRun(gfxPangoFontGroup *aGroup,
const PRUint8* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams);
gfxPangoTextRun(gfxPangoFontGroup *aGroup,
const PRUnichar* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams);
~gfxPangoTextRun();
virtual void Draw(gfxContext *aContext, gfxPoint pt);
virtual gfxFloat Measure(gfxContext *aContext);
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8* aFlags);
virtual PRUint8 GetCharFlags(PRUint32 aOffset);
virtual PRUint32 GetLength();
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore);
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth);
virtual void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth);
virtual void DrawSpecialString(gfxContext* aContext, gfxPoint aPt,
SpecialString aString);
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider* aBreakProvider);
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider* aProvider,
gfxFloat* aAdvanceWidthDelta);
virtual Metrics MeasureTextSpecialString(SpecialString aString,
PRBool aTightBoundingBox);
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider);
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString);
virtual gfxFont::Metrics GetDecorationMetrics();
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider* aBreakProvider,
PRBool aSuppressInitialBreak,
Metrics* aMetrics, PRBool aTightBoundingBox,
PRBool* aUsedHyphenation,
PRUint32* aLastBreak);
virtual void FlushSpacingCache(PRUint32 aStart);
virtual void SetSpacing(const nsTArray<gfxFloat>& spacingArray);
virtual const nsTArray<gfxFloat> *const GetSpacing() const;
/**
* This class records the information associated with a character in the
* input string. It's optimized for the case where there is one glyph
* representing that character alone.
*/
class CompressedGlyph {
public:
CompressedGlyph() { mValue = 0; }
enum {
// Indicates that a cluster starts at this character and can be
// rendered using a single glyph with a reasonable advance offset
// and no special glyph offset. A "reasonable" advance offset is
// one that is a) a multiple of a pixel and b) fits in the available
// bits (currently 14). We should revisit this, especially a),
// if we want to support subpixel-aligned text.
FLAG_IS_SIMPLE_GLYPH = 0x80000000U,
// Indicates that a linebreak is allowed before this character
FLAG_CAN_BREAK_BEFORE = 0x40000000U,
ADVANCE_MASK = 0x3FFF0000U,
ADVANCE_SHIFT = 16,
GLYPH_MASK = 0x0000FFFFU,
// Non-simple glyphs have the following tags
TAG_MASK = 0x000000FFU,
// Indicates that a cluster starts at this character and is rendered
// using one or more glyphs which cannot be represented here.
// Look up the DetailedGlyph table instead.
TAG_COMPLEX_CLUSTER = 0x00U,
// Indicates that a cluster starts at this character but is rendered
// as part of a ligature starting in a previous cluster.
// NOTE: we divide up the ligature's width by the number of clusters
// to get the width assigned to each cluster.
TAG_LIGATURE_CONTINUATION = 0x01U,
// Values where the upper 28 bits equal 0x80 are reserved for
// non-cluster-start characters (see IsClusterStart below)
// Indicates that a cluster does not start at this character, this is
// a low UTF16 surrogate
TAG_LOW_SURROGATE = 0x80U,
// Indicates that a cluster does not start at this character, this is
// part of a cluster starting with an earlier character (but not
// a low surrogate).
TAG_CLUSTER_CONTINUATION = 0x81U
};
// Returns true if the glyph ID aGlyph fits into the compressed representation
static PRBool IsSimpleGlyphID(PRUint32 aGlyph) {
return (aGlyph & GLYPH_MASK) == aGlyph;
}
// Returns true if the advance aAdvance fits into the compressed representation
static PRBool IsSimpleAdvance(PRUint32 aAdvance) {
return (aAdvance & (ADVANCE_MASK >> ADVANCE_SHIFT)) == aAdvance;
}
PRBool IsSimpleGlyph() { return (mValue & FLAG_IS_SIMPLE_GLYPH) != 0; }
PRBool IsComplex(PRUint32 aTag) { return (mValue & (FLAG_IS_SIMPLE_GLYPH|TAG_MASK)) == aTag; }
PRBool IsComplexCluster() { return IsComplex(TAG_COMPLEX_CLUSTER); }
PRBool IsLigatureContinuation() { return IsComplex(TAG_LIGATURE_CONTINUATION); }
PRBool IsLowSurrogate() { return IsComplex(TAG_LOW_SURROGATE); }
PRBool IsClusterStart() { return (mValue & (FLAG_IS_SIMPLE_GLYPH|0x80U)) != 0x80U; }
PRUint32 GetSimpleAdvance() { return (mValue & ADVANCE_MASK) >> ADVANCE_SHIFT; }
PRUint32 GetSimpleGlyph() { return mValue & GLYPH_MASK; }
PRUint32 GetComplexTag() { return mValue & TAG_MASK; }
PRBool CanBreakBefore() { return (mValue & FLAG_CAN_BREAK_BEFORE) != 0; }
// Returns FLAG_CAN_BREAK_BEFORE if the setting changed, 0 otherwise
PRUint32 SetCanBreakBefore(PRBool aCanBreakBefore) {
PRUint32 breakMask = aCanBreakBefore*FLAG_CAN_BREAK_BEFORE;
PRUint32 toggle = breakMask ^ (mValue & FLAG_CAN_BREAK_BEFORE);
mValue ^= toggle;
return toggle;
}
void SetSimpleGlyph(PRUint32 aAdvance, PRUint32 aGlyph) {
NS_ASSERTION(IsSimpleAdvance(aAdvance), "Advance overflow");
NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | FLAG_IS_SIMPLE_GLYPH |
(aAdvance << ADVANCE_SHIFT) | aGlyph;
}
void SetComplex(PRUint32 aTag) { mValue = (mValue & FLAG_CAN_BREAK_BEFORE) | aTag; }
void SetComplexCluster() { SetComplex(TAG_COMPLEX_CLUSTER); }
void SetLowSurrogate() { SetComplex(TAG_LOW_SURROGATE); }
void SetLigatureContinuation() { SetComplex(TAG_LIGATURE_CONTINUATION); }
void SetClusterContinuation() { SetComplex(TAG_CLUSTER_CONTINUATION); }
private:
PRUint32 mValue;
};
struct DetailedGlyph {
PRUint32 mIsLastGlyph:1;
// mGlyphID == 2^31 means "missing glyph"
PRUint32 mGlyphID:31;
float mAdvance, mXOffset, mYOffset;
// This is the ID of a missing glyph in a details record. All "missing" glyphs
// are converted to a detailed glyph record with this glyph ID.
enum {
DETAILED_MISSING_GLYPH = 1U << 30
};
};
// The text is divided into GlyphRuns at Pango item and text segment boundaries
struct GlyphRun {
PangoFont* mPangoFont; // strong ref; can't be null
cairo_scaled_font_t* mCairoFont; // could be null
PRUint32 mCharacterOffset; // into original UTF16 string
~GlyphRun() {
if (mCairoFont) {
cairo_scaled_font_destroy(mCairoFont);
}
if (mPangoFont) {
g_object_unref(mPangoFont);
}
}
};
class GlyphRunIterator {
public:
GlyphRunIterator(gfxPangoTextRun* aTextRun, PRUint32 aStart, PRUint32 aLength)
: mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) {
mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart);
}
PRBool NextRun();
GlyphRun* GetGlyphRun() { return mGlyphRun; }
PRUint32 GetStringStart() { return mStringStart; }
PRUint32 GetStringEnd() { return mStringEnd; }
private:
gfxPangoTextRun* mTextRun;
GlyphRun* mGlyphRun;
PRUint32 mStringStart;
PRUint32 mStringEnd;
PRUint32 mNextIndex;
PRUint32 mStartOffset;
PRUint32 mEndOffset;
};
friend class GlyphRunIterator;
friend class FontSelector;
// **** Initialization helpers ****
private:
nsString mString;
nsCString mUTF8String;
// If aUTF16Text is null, then the string contains no characters >= 0x100
void Init(gfxTextRunFactory::Parameters* aParams, const gchar* aUTF8Text,
PRUint32 aUTF8Length, PRUint32 aUTF8HeaderLength, const PRUnichar* aUTF16Text,
PRUint32 aUTF16Length);
void SetupClusterBoundaries(const gchar* aUTF8, PRUint32 aUTF8Length,
PRUint32 aUTF16Offset, PangoAnalysis* aAnalysis);
nsresult AddGlyphRun(PangoFont* aFont, PRUint32 aUTF16Offset);
// Returns NS_ERROR_FAILURE if there's a missing glyph
nsresult SetGlyphs(const gchar* aUTF8, PRUint32 aUTF8Length,
PRUint32* aUTF16Offset, PangoGlyphString* aGlyphs,
PangoGlyphUnit aOverrideSpaceWidth,
PRBool aAbortOnMissingGlyph);
// If aUTF16Text is null, then the string contains no characters >= 0x100.
// Returns NS_ERROR_FAILURE if we require the itemizing path
nsresult CreateGlyphRunsFast(const gchar* aUTF8, PRUint32 aUTF8Length,
const PRUnichar* aUTF16Text, PRUint32 aUTF16Length);
void CreateGlyphRunsItemizing(const gchar* aUTF8, PRUint32 aUTF8Length,
PRUint32 aUTF8HeaderLength);
gfxPangoFontGroup *mGroup;
// **** general helpers ****
PangoLayout *mPangoLayout;
int mWidth;
void SetupPangoContextDirection();
static void SetupCairoFont(cairo_t* aCR, GlyphRun* aGlyphRun);
// Returns the index of the GlyphRun containing the given offset.
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
// Computes the x-advance for a given cluster starting at aClusterOffset. Does
// not include any spacing. Result is in device pixels.
gfxFloat ComputeClusterAdvance(PRUint32 aClusterOffset);
int MeasureOrDraw(gfxContext *aContext, PRBool aDraw, gfxPoint aPt);
int MeasureOrDrawItemizing(gfxContext *aContext, PRBool aDraw,
gfxPoint aPt, PRBool aIsRTL,
gfxPangoFont *aFont);
int DrawFromCache(gfxContext *aContext, gfxPoint aPt);
// **** ligature helpers ****
// (Pango does the actual ligaturization, but we need to do a bunch of stuff
// to handle requests that begin or end inside a ligature)
nsTArray<gfxFloat> mSpacing;
nsTArray<PRInt32> mUTF8Spacing;
nsTArray<TextSegment> mSegments;
struct LigatureData {
PRUint32 mStartOffset;
PRUint32 mEndOffset;
PRUint32 mClusterCount;
PRUint32 mPartClusterIndex;
gfxFloat mLigatureWidth; // appunits
gfxFloat mBeforeSpacing; // appunits
gfxFloat mAfterSpacing; // appunits
};
// if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero
LigatureData ComputeLigatureData(PRUint32 aPartOffset, PropertyProvider* aProvider);
void GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
PropertyProvider* aProvider, PropertyProvider::Spacing* aSpacing);
PRBool GetAdjustedSpacingArray(PRUint32 aStart, PRUint32 aEnd,
PropertyProvider* aProvider,
nsTArray<PropertyProvider::Spacing>* aSpacing);
void DrawPartialLigature(gfxContext* aCtx, PRUint32 aOffset,
const gfxRect* aDirtyRect, gfxPoint* aPt,
PropertyProvider* aProvider);
// result in appunits
void ShrinkToLigatureBoundaries(PRUint32* aStart, PRUint32* aEnd);
gfxFloat GetPartialLigatureWidth(PRUint32 aStart, PRUint32 aEnd, PropertyProvider* aProvider);
void AccumulatePartialLigatureMetrics(PangoFont* aPangoFont,
PRUint32 aOffset, PropertyProvider* aProvider,
Metrics* aMetrics);
// **** measurement helper ****
void AccumulatePangoMetricsForRun(PangoFont* aPangoFont, PRUint32 aStart,
PRUint32 aEnd, PropertyProvider* aProvider,
Metrics* aMetrics);
// **** drawing helpers ****
typedef void (* CairoGlyphProcessorCallback)
(void* aClosure, cairo_glyph_t* aGlyphs, int aNumGlyphs);
void ProcessCairoGlyphsWithSpacing(CairoGlyphProcessorCallback aCB, void* aClosure,
gfxPoint* aPt, PRUint32 aStart, PRUint32 aEnd,
PropertyProvider::Spacing* aSpacing);
void ProcessCairoGlyphs(CairoGlyphProcessorCallback aCB, void* aClosure,
gfxPoint* aPt, PRUint32 aStart, PRUint32 aEnd,
PropertyProvider* aProvider);
static void CairoShowGlyphs(void* aClosure, cairo_glyph_t* aGlyphs, int aNumGlyphs);
static void CairoGlyphsToPath(void* aClosure, cairo_glyph_t* aGlyphs, int aNumGlyphs);
nsRefPtr<gfxPangoFontGroup> mFontGroup;
// All our glyph data is in logical order, not visual
nsAutoArrayPtr<CompressedGlyph> mCharacterGlyphs;
nsAutoArrayPtr<nsAutoArrayPtr<DetailedGlyph> > mDetailedGlyphs; // only non-null if needed
nsAutoTArray<GlyphRun,1> mGlyphRuns;
PRUint32 mCharacterCount;
};
#endif /* GFX_PANGOFONTS_H */

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

@ -58,15 +58,17 @@ public:
static nsresult Init();
static void Shutdown();
/* Will return a pointer to a gfxTextRun, either from the cache
* or a newly created (and cached) run.
*
* The caller does not have to addref the result, as long as
* it is not used past another call to GetOrMakeTextRun, at which point
* it may be evicted.
/* Will return a pointer to a gfxTextRun, which may or may not be from
* the cache. If aCallerOwns is set to true, the caller owns the textrun
* and must delete it. Otherwise the returned textrun is only valid until
* the next GetOrMakeTextRun call and the caller must not delete it.
*/
gfxTextRun *GetOrMakeTextRun (gfxFontGroup *aFontGroup, const nsAString& aString);
gfxTextRun *GetOrMakeTextRun (gfxFontGroup *aFontGroup, const nsACString& aString);
gfxTextRun *GetOrMakeTextRun (gfxContext* aContext, gfxFontGroup *aFontGroup,
const char *aString, PRUint32 aLength, gfxFloat aDevToApp,
PRBool aIsRTL, PRBool aEnableSpacing, PRBool *aCallerOwns);
gfxTextRun *GetOrMakeTextRun (gfxContext* aContext, gfxFontGroup *aFontGroup,
const PRUnichar *aString, PRUint32 aLength, gfxFloat aDevToApp,
PRBool aIsRTL, PRBool aEnableSpacing, PRBool *aCallerOwns);
protected:
gfxTextRunCache();
@ -146,8 +148,10 @@ protected:
TextRunEntry(gfxTextRun *tr) : textRun(tr), lastUse(PR_Now()) { }
void Used() { lastUse = PR_Now(); }
nsRefPtr<gfxTextRun> textRun;
PRTime lastUse;
gfxTextRun* textRun;
PRTime lastUse;
~TextRunEntry() { delete textRun; }
};
typedef FontGroupAndStringT<nsAString, nsString> FontGroupAndString;
@ -156,9 +160,6 @@ protected:
typedef FontGroupAndStringHashKeyT<FontGroupAndString> FontGroupAndStringHashKey;
typedef FontGroupAndStringHashKeyT<FontGroupAndCString> FontGroupAndCStringHashKey;
//nsRefPtrHashtable<FontGroupAndStringHashKey, gfxTextRun> mHashTableUTF16;
//nsRefPtrHashtable<FontGroupAndCStringHashKey, gfxTextRun> mHashTableASCII;
nsClassHashtable<FontGroupAndStringHashKey, TextRunEntry> mHashTableUTF16;
nsClassHashtable<FontGroupAndCStringHashKey, TextRunEntry> mHashTableASCII;

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

@ -420,8 +420,14 @@ public:
gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle);
virtual ~gfxWindowsFontGroup();
virtual gfxTextRun *MakeTextRun(const nsAString& aString);
virtual gfxTextRun *MakeTextRun(const nsACString& aString);
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle) {
NS_ERROR("NOT IMPLEMENTED");
return nsnull;
}
virtual gfxTextRun *MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams);
virtual gfxTextRun *MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams);
const nsACString& GetGenericFamily() const {
return mGenericFamily;
@ -478,7 +484,7 @@ private:
*
**********************************************************************/
class THEBES_API gfxWindowsTextRun : public gfxTextRun {
class THEBES_API gfxWindowsTextRun {
public:
gfxWindowsTextRun(const nsAString& aString, gfxWindowsFontGroup *aFontGroup);
gfxWindowsTextRun(const nsACString& aString, gfxWindowsFontGroup *aFontGroup);
@ -489,6 +495,9 @@ public:
virtual void SetSpacing(const nsTArray<gfxFloat>& spacingArray);
virtual const nsTArray<gfxFloat> *const GetSpacing() const;
void SetRightToLeft(PRBool aIsRTL) { mIsRTL = aIsRTL; }
PRBool IsRightToLeft() { return mIsRTL; }
private:
double MeasureOrDrawFast(gfxContext *aContext, PRBool aDraw, gfxPoint pt);
@ -502,8 +511,9 @@ private:
nsString mString;
nsCString mCString;
const PRBool mIsASCII;
const PRPackedBool mIsASCII;
PRPackedBool mIsRTL;
nsRefPtr<gfxWindowsFont> mFallbackFont;
/* cached values */

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

@ -315,10 +315,156 @@ gfxAtsuiFontGroup::~gfxAtsuiFontGroup()
ATSUDisposeFontFallbacks(mFallbacks);
}
gfxTextRun*
gfxAtsuiFontGroup::MakeTextRun(const nsAString& aString)
class gfxWrapperTextRun : public gfxTextRun {
public:
gfxWrapperTextRun(gfxAtsuiFontGroup *aGroup,
const PRUint8* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams)
: gfxTextRun(aParams, PR_TRUE),
mContext(aParams->mContext),
mInner(NS_ConvertASCIItoUTF16(nsDependentCSubstring(reinterpret_cast<const char*>(aString),
reinterpret_cast<const char*>(aString + aLength))),
aGroup),
mLength(aLength)
{
mInner.SetRightToLeft(IsRightToLeft());
}
gfxWrapperTextRun(gfxAtsuiFontGroup *aGroup,
const PRUnichar* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams)
: gfxTextRun(aParams, PR_TRUE), mContext(aParams->mContext),
mInner(nsDependentSubstring(aString, aString + aLength), aGroup),
mLength(aLength)
{
mInner.SetRightToLeft(IsRightToLeft());
}
~gfxWrapperTextRun() {}
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8* aFlags)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual PRUint8 GetCharFlags(PRUint32 aOffset)
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
virtual PRUint32 GetLength()
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore)
{ NS_ERROR("NOT IMPLEMENTED"); return PR_FALSE; }
virtual void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual void DrawSpecialString(gfxContext* aContext, gfxPoint aPt,
SpecialString aString)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider* aBreakProvider)
{ NS_ERROR("NOT IMPLEMENTED"); return Metrics(); }
virtual Metrics MeasureTextSpecialString(SpecialString aString,
PRBool aTightBoundingBox)
{ NS_ERROR("NOT IMPLEMENTED"); return Metrics(); }
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString)
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
virtual gfxFont::Metrics GetDecorationMetrics()
{ NS_ERROR("NOT IMPLEMENTED"); return gfxFont::Metrics(); }
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider* aProvider,
gfxFloat* aAdvanceWidthDelta)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider* aProvider,
PRBool aSuppressInitialBreak,
Metrics* aMetrics, PRBool aTightBoundingBox,
PRBool* aUsedHyphenation,
PRUint32* aLastBreak)
{ NS_ERROR("NOT IMPLEMENTED"); return 0; }
virtual void FlushSpacingCache(PRUint32 aStart)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth);
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider);
virtual void SetContext(gfxContext* aContext) { mContext = aContext; }
private:
gfxContext* mContext;
gfxAtsuiTextRun mInner;
PRUint32 mLength;
void SetupSpacingFromProvider(PropertyProvider* aProvider);
};
#define ROUND(x) floor((x) + 0.5)
void
gfxWrapperTextRun::SetupSpacingFromProvider(PropertyProvider* aProvider)
{
return new gfxAtsuiTextRun(aString, this);
if (!(mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING))
return;
NS_ASSERTION(mFlags & gfxTextRunFactory::TEXT_ABSOLUTE_SPACING,
"Can't handle relative spacing");
nsAutoTArray<PropertyProvider::Spacing,200> spacing;
spacing.AppendElements(mLength);
aProvider->GetSpacing(0, mLength, spacing.Elements());
nsTArray<gfxFloat> spaceArray;
PRUint32 i;
gfxFloat offset = 0;
for (i = 0; i < mLength; ++i) {
NS_ASSERTION(spacing.Elements()[i].mBefore == 0,
"Can't handle before-spacing!");
gfxFloat nextOffset = offset + spacing.Elements()[i].mAfter/mPixelsToAppUnits;
spaceArray.AppendElement(ROUND(nextOffset) - ROUND(offset));
offset = nextOffset;
}
mInner.SetSpacing(spaceArray);
}
void
gfxWrapperTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth)
{
NS_ASSERTION(aStart == 0 && aLength == mLength, "Can't handle substrings");
SetupSpacingFromProvider(aBreakProvider);
gfxPoint pt(aPt.x/mPixelsToAppUnits, aPt.y/mPixelsToAppUnits);
return mInner.Draw(mContext, pt);
}
gfxFloat
gfxWrapperTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider)
{
NS_ASSERTION(aStart == 0 && aLength == mLength, "Can't handle substrings");
SetupSpacingFromProvider(aBreakProvider);
return mInner.Measure(mContext)*mPixelsToAppUnits;
}
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams)
{
return new gfxWrapperTextRun(this, aString, aLength, aParams);
}
gfxTextRun *
gfxAtsuiFontGroup::MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams)
{
return new gfxWrapperTextRun(this, aString, aLength, aParams);
}
gfxAtsuiFont*

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

@ -649,14 +649,6 @@ gfxContext::Mask(gfxASurface *surface, gfxPoint offset)
cairo_mask_surface(mCairo, surface->CairoSurface(), offset.x, offset.y);
}
// fonts?
void
gfxContext::DrawTextRun(gfxTextRun *text, gfxPoint pt)
{
if (text)
text->Draw(this, pt);
}
void
gfxContext::Paint(gfxFloat alpha)
{

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -85,53 +85,126 @@ gfxTextRunCache::Shutdown()
}
}
gfxTextRun*
gfxTextRunCache::GetOrMakeTextRun (gfxFontGroup *aFontGroup, const nsAString& aString)
static PRUint32 ComputeFlags(PRBool aIsRTL, PRBool aEnableSpacing)
{
if (gDisableCache)
return aFontGroup->MakeTextRun(aString);
PRUint32 flags = gfxTextRunFactory::TEXT_HAS_SURROGATES;
if (aIsRTL) {
flags |= gfxTextRunFactory::TEXT_IS_RTL;
}
if (aEnableSpacing) {
flags |= gfxTextRunFactory::TEXT_ENABLE_SPACING |
gfxTextRunFactory::TEXT_ABSOLUTE_SPACING |
gfxTextRunFactory::TEXT_ENABLE_NEGATIVE_SPACING;
}
return flags;
}
// Evict first, to make sure that the textrun we return is live.
EvictUTF16();
gfxTextRun*
gfxTextRunCache::GetOrMakeTextRun (gfxContext* aContext, gfxFontGroup *aFontGroup,
const PRUnichar *aString, PRUint32 aLength, gfxFloat aDevToApp,
PRBool aIsRTL, PRBool aEnableSpacing, PRBool *aCallerOwns)
{
gfxSkipChars skipChars;
// Choose pessimistic flags since we don't want to bother analyzing the string
gfxTextRunFactory::Parameters params =
{ aContext, nsnull, nsnull, &skipChars, nsnull, 0, aDevToApp,
ComputeFlags(aIsRTL, aEnableSpacing) };
gfxTextRun *tr;
TextRunEntry *entry;
FontGroupAndString key(aFontGroup, &aString);
gfxTextRun* tr = nsnull;
// Don't cache textruns that use spacing
if (!gDisableCache && !aEnableSpacing) {
// Evict first, to make sure that the textrun we return is live.
EvictUTF16();
TextRunEntry *entry;
nsDependentSubstring keyStr(aString, aString + aLength);
FontGroupAndString key(aFontGroup, &keyStr);
if (mHashTableUTF16.Get(key, &entry)) {
entry->Used();
tr = entry->textRun.get();
if (mHashTableUTF16.Get(key, &entry)) {
gfxTextRun *cachedTR = entry->textRun;
// Check that this matches what we wanted. If it doesn't, we leave
// this cache entry alone and return a fresh, caller-owned textrun
// below.
if (cachedTR->GetPixelsToAppUnits() == aDevToApp &&
cachedTR->IsRightToLeft() == aIsRTL) {
entry->Used();
tr = cachedTR;
tr->SetContext(aContext);
}
} else {
tr = aFontGroup->MakeTextRun(aString, aLength, &params);
entry = new TextRunEntry(tr);
key.Realize();
mHashTableUTF16.Put(key, entry);
}
}
if (tr) {
*aCallerOwns = PR_FALSE;
} else {
tr = aFontGroup->MakeTextRun(aString);
entry = new TextRunEntry(tr);
key.Realize();
mHashTableUTF16.Put(key, entry);
// Textrun is not in the cache for some reason.
*aCallerOwns = PR_TRUE;
tr = aFontGroup->MakeTextRun(aString, aLength, &params);
}
if (tr) {
// We don't want to have to reconstruct the string
tr->RememberText(aString, aLength);
}
return tr;
}
gfxTextRun*
gfxTextRunCache::GetOrMakeTextRun (gfxFontGroup *aFontGroup, const nsACString& aString)
gfxTextRunCache::GetOrMakeTextRun (gfxContext* aContext, gfxFontGroup *aFontGroup,
const char *aString, PRUint32 aLength, gfxFloat aDevToApp,
PRBool aIsRTL, PRBool aEnableSpacing, PRBool *aCallerOwns)
{
if (gDisableCache)
return aFontGroup->MakeTextRun(aString);
gfxSkipChars skipChars;
// Choose pessimistic flags since we don't want to bother analyzing the string
gfxTextRunFactory::Parameters params =
{ aContext, nsnull, nsnull, &skipChars, nsnull, 0, aDevToApp,
ComputeFlags(aIsRTL, aEnableSpacing) };
const PRUint8* str = NS_REINTERPRET_CAST(const PRUint8*, aString);
// Evict first, to make sure that the textrun we return is live.
EvictASCII();
gfxTextRun* tr = nsnull;
// Don't cache textruns that use spacing
if (!gDisableCache && !aEnableSpacing) {
// Evict first, to make sure that the textrun we return is live.
EvictASCII();
TextRunEntry *entry;
nsDependentCSubstring keyStr(aString, aString + aLength);
FontGroupAndCString key(aFontGroup, &keyStr);
gfxTextRun *tr;
TextRunEntry *entry;
FontGroupAndCString key(aFontGroup, &aString);
if (mHashTableASCII.Get(key, &entry)) {
gfxTextRun *cachedTR = entry->textRun;
// Check that this matches what we wanted. If it doesn't, we leave
// this cache entry alone and return a fresh, caller-owned textrun
// below.
if (cachedTR->GetPixelsToAppUnits() == aDevToApp &&
cachedTR->IsRightToLeft() == aIsRTL) {
entry->Used();
tr = cachedTR;
tr->SetContext(aContext);
}
} else {
tr = aFontGroup->MakeTextRun(str, aLength, &params);
entry = new TextRunEntry(tr);
key.Realize();
mHashTableASCII.Put(key, entry);
}
}
if (mHashTableASCII.Get(key, &entry)) {
entry->Used();
tr = entry->textRun.get();
if (tr) {
*aCallerOwns = PR_FALSE;
} else {
tr = aFontGroup->MakeTextRun(aString);
entry = new TextRunEntry(tr);
key.Realize();
mHashTableASCII.Put(key, entry);
// Textrun is not in the cache for some reason.
*aCallerOwns = PR_TRUE;
tr = aFontGroup->MakeTextRun(str, aLength, &params);
}
if (tr) {
// We don't want to have to reconstruct the string
tr->RememberText(str, aLength);
}
return tr;

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

@ -513,24 +513,153 @@ gfxWindowsFontGroup::~gfxWindowsFontGroup()
}
gfxTextRun *
gfxWindowsFontGroup::MakeTextRun(const nsAString& aString)
{
if (aString.IsEmpty()) {
NS_WARNING("It is illegal to create a gfxTextRun with empty strings");
return nsnull;
class gfxWrapperTextRun : public gfxTextRun {
public:
gfxWrapperTextRun(gfxWindowsFontGroup *aGroup,
const PRUint8* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams)
: gfxTextRun(aParams, PR_TRUE), mContext(aParams->mContext),
mInner(nsDependentCSubstring(reinterpret_cast<const char*>(aString),
reinterpret_cast<const char*>(aString + aLength)),
aGroup),
mLength(aLength)
{
mInner.SetRightToLeft(IsRightToLeft());
}
return new gfxWindowsTextRun(aString, this);
gfxWrapperTextRun(gfxWindowsFontGroup *aGroup,
const PRUnichar* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams)
: gfxTextRun(aParams, PR_TRUE), mContext(aParams->mContext),
mInner(nsDependentSubstring(aString, aString + aLength), aGroup),
mLength(aLength)
{
mInner.SetRightToLeft(IsRightToLeft());
}
~gfxWrapperTextRun() {}
virtual void GetCharFlags(PRUint32 aStart, PRUint32 aLength,
PRUint8* aFlags)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual PRUint8 GetCharFlags(PRUint32 aOffset)
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual PRUint32 GetLength()
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRPackedBool* aBreakBefore)
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual void DrawToPath(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual void DrawSpecialString(gfxContext* aContext, gfxPoint aPt,
SpecialString aString)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual Metrics MeasureText(PRUint32 aStart, PRUint32 aLength,
PRBool aTightBoundingBox,
PropertyProvider* aBreakProvider)
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual Metrics MeasureTextSpecialString(SpecialString aString,
PRBool aTightBoundingBox)
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual gfxFloat GetAdvanceWidthSpecialString(SpecialString aString)
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual gfxFont::Metrics GetDecorationMetrics()
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual void SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
TextProvider* aProvider,
gfxFloat* aAdvanceWidthDelta)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual PRUint32 BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
PRBool aLineBreakBefore, gfxFloat aWidth,
PropertyProvider* aProvider,
PRBool aSuppressInitialBreak,
Metrics* aMetrics, PRBool aTightBoundingBox,
PRBool* aUsedHyphenation,
PRUint32* aLastBreak)
{ NS_ERROR("NOT IMPLEMENTED"); for (;;) ; }
virtual void FlushSpacingCache(PRUint32 aStart)
{ NS_ERROR("NOT IMPLEMENTED"); }
virtual void Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth);
virtual gfxFloat GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider);
virtual void SetContext(gfxContext* aContext) { mContext = aContext; }
private:
gfxContext* mContext;
gfxWindowsTextRun mInner;
PRUint32 mLength;
void SetupSpacingFromProvider(PropertyProvider* aProvider);
};
void
gfxWrapperTextRun::SetupSpacingFromProvider(PropertyProvider* aProvider)
{
if (!(mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING))
return;
NS_ASSERTION(mFlags & gfxTextRunFactory::TEXT_ABSOLUTE_SPACING,
"Can't handle relative spacing");
nsAutoTArray<PropertyProvider::Spacing,200> spacing;
spacing.AppendElements(mLength);
aProvider->GetSpacing(0, mLength, spacing.Elements());
nsTArray<gfxFloat> spaceArray;
PRUint32 i;
gfxFloat offset = 0;
for (i = 0; i < mLength; ++i) {
NS_ASSERTION(spacing.Elements()[i].mBefore == 0,
"Can't handle before-spacing!");
gfxFloat nextOffset = offset + spacing.Elements()[i].mAfter/mPixelsToAppUnits;
spaceArray.AppendElement(ROUND(nextOffset) - ROUND(offset));
offset = nextOffset;
}
mInner.SetSpacing(spaceArray);
}
void
gfxWrapperTextRun::Draw(gfxContext *aContext, gfxPoint aPt,
PRUint32 aStart, PRUint32 aLength,
const gfxRect* aDirtyRect,
PropertyProvider* aBreakProvider,
gfxFloat* aAdvanceWidth)
{
NS_ASSERTION(aStart == 0 && aLength == mLength, "Can't handle substrings");
SetupSpacingFromProvider(aBreakProvider);
gfxPoint pt(aPt.x/mPixelsToAppUnits, aPt.y/mPixelsToAppUnits);
return mInner.Draw(mContext, pt);
}
gfxFloat
gfxWrapperTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
PropertyProvider* aBreakProvider)
{
NS_ASSERTION(aStart == 0 && aLength == mLength, "Can't handle substrings");
SetupSpacingFromProvider(aBreakProvider);
return mInner.Measure(mContext)*mPixelsToAppUnits;
}
gfxTextRun *
gfxWindowsFontGroup::MakeTextRun(const nsACString& aString)
gfxWindowsFontGroup::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
Parameters* aParams)
{
if (aString.IsEmpty()) {
NS_WARNING("It is illegal to create a gfxTextRun with empty strings");
return nsnull;
}
return new gfxWindowsTextRun(aString, this);
return new gfxWrapperTextRun(this, aString, aLength, aParams);
}
gfxTextRun *
gfxWindowsFontGroup::MakeTextRun(const PRUint8* aString, PRUint32 aLength,
Parameters* aParams)
{
return new gfxWrapperTextRun(this, aString, aLength, aParams);
}
/**********************************************************************