зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
326c234dbe
Коммит
fa82daaaaf
|
@ -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, ¶ms);
|
||||
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, ¶ms);
|
||||
}
|
||||
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, ¶ms);
|
||||
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, ¶ms);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
|
Загрузка…
Ссылка в новой задаче