mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
GetWidth optimizations for Unix. Bug 36146. Authors Tomi.Leppikangas@oulu.fi, Roland.Mainz@informatik.med.uni-giessen.de; r=shanjian,smontagu; sr=rbs, darin
This commit is contained in:
parent
6b05f3b883
commit
52121ade9f
@ -234,7 +234,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle) = 0;
|
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle) = 0;
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11)
|
||||||
/**
|
/**
|
||||||
* Returns the average character width
|
* Returns the average character width
|
||||||
*/
|
*/
|
||||||
|
@ -608,7 +608,7 @@ public:
|
|||||||
NS_IMETHOD GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
|
NS_IMETHOD GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
|
||||||
nsTextDimensions& aDimensions, PRInt32* aFontID = nsnull) = 0;
|
nsTextDimensions& aDimensions, PRInt32* aFontID = nsnull) = 0;
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11)
|
||||||
/**
|
/**
|
||||||
* Given an available width and an array of break points,
|
* Given an available width and an array of break points,
|
||||||
* returns the dimensions (in app units) of the text that fit and
|
* returns the dimensions (in app units) of the text that fit and
|
||||||
@ -888,6 +888,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
#define NS_RENDERING_HINT_ARABIC_SHAPING 0x8
|
#define NS_RENDERING_HINT_ARABIC_SHAPING 0x8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bit, when set, indicates that gfx supports GetTextDimensions()
|
||||||
|
*/
|
||||||
|
#define NS_RENDERING_HINT_FAST_MEASURE 0x10
|
||||||
|
|
||||||
//flags for copy CopyOffScreenBits
|
//flags for copy CopyOffScreenBits
|
||||||
|
|
||||||
//when performing the blit, use the region, if any,
|
//when performing the blit, use the region, if any,
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
#include "nsXFontNormal.h"
|
#include "nsXFontNormal.h"
|
||||||
#include "nsX11AlphaBlend.h"
|
#include "nsX11AlphaBlend.h"
|
||||||
#include "nsXFontAAScaledBitmap.h"
|
#include "nsXFontAAScaledBitmap.h"
|
||||||
|
#include "nsUnicharUtils.h"
|
||||||
#ifdef ENABLE_X_FONT_BANNING
|
#ifdef ENABLE_X_FONT_BANNING
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#endif /* ENABLE_X_FONT_BANNING */
|
#endif /* ENABLE_X_FONT_BANNING */
|
||||||
@ -1433,6 +1434,9 @@ void nsFontMetricsGTK::RealizeFont()
|
|||||||
PRUnichar space = (PRUnichar)' ';
|
PRUnichar space = (PRUnichar)' ';
|
||||||
mSpaceWidth = NSToCoordRound(ft->GetWidth(&space, 1) * f);
|
mSpaceWidth = NSToCoordRound(ft->GetWidth(&space, 1) * f);
|
||||||
|
|
||||||
|
PRUnichar averageX = (PRUnichar)'x';
|
||||||
|
mAveCharWidth = NSToCoordRound(ft->GetWidth(&averageX, 1) * f);
|
||||||
|
|
||||||
unsigned long pr = 0;
|
unsigned long pr = 0;
|
||||||
if (ft->getXHeight(pr)) {
|
if (ft->getXHeight(pr)) {
|
||||||
mXHeight = nscoord(pr * f);
|
mXHeight = nscoord(pr * f);
|
||||||
@ -1501,17 +1505,22 @@ void nsFontMetricsGTK::RealizeFont()
|
|||||||
|
|
||||||
mMaxAdvance = nscoord(fontInfo->max_bounds.width * f);
|
mMaxAdvance = nscoord(fontInfo->max_bounds.width * f);
|
||||||
|
|
||||||
gint rawWidth;
|
gint rawWidth, rawAverage;
|
||||||
if ((fontInfo->min_byte1 == 0) && (fontInfo->max_byte1 == 0)) {
|
if ((fontInfo->min_byte1 == 0) && (fontInfo->max_byte1 == 0)) {
|
||||||
rawWidth = xFont->TextWidth8(" ", 1);
|
rawWidth = xFont->TextWidth8(" ", 1);
|
||||||
|
rawAverage = xFont->TextWidth8("x", 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
XChar2b _16bit_space;
|
XChar2b _16bit_space, _16bit_x;
|
||||||
_16bit_space.byte1 = 0;
|
_16bit_space.byte1 = 0;
|
||||||
_16bit_space.byte2 = ' ';
|
_16bit_space.byte2 = ' ';
|
||||||
|
_16bit_x.byte1 = 0;
|
||||||
|
_16bit_x.byte2 = 'x';
|
||||||
rawWidth = xFont->TextWidth16(&_16bit_space, sizeof(_16bit_space)/2);
|
rawWidth = xFont->TextWidth16(&_16bit_space, sizeof(_16bit_space)/2);
|
||||||
|
rawAverage = xFont->TextWidth16(&_16bit_x, sizeof( _16bit_x)/2);
|
||||||
}
|
}
|
||||||
mSpaceWidth = NSToCoordRound(rawWidth * f);
|
mSpaceWidth = NSToCoordRound(rawWidth * f);
|
||||||
|
mAveCharWidth = NSToCoordRound(rawAverage * f);
|
||||||
|
|
||||||
unsigned long pr = 0;
|
unsigned long pr = 0;
|
||||||
if (xFont->GetXFontProperty(XA_X_HEIGHT, &pr) &&
|
if (xFont->GetXFontProperty(XA_X_HEIGHT, &pr) &&
|
||||||
@ -1681,6 +1690,12 @@ NS_IMETHODIMP nsFontMetricsGTK::GetMaxAdvance(nscoord &aAdvance)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsFontMetricsGTK::GetAveCharWidth(nscoord &aAveCharWidth)
|
||||||
|
{
|
||||||
|
aAveCharWidth = mAveCharWidth;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsFontMetricsGTK::GetFont(const nsFont*& aFont)
|
NS_IMETHODIMP nsFontMetricsGTK::GetFont(const nsFont*& aFont)
|
||||||
{
|
{
|
||||||
aFont = mFont;
|
aFont = mFont;
|
||||||
@ -1705,6 +1720,106 @@ NS_IMETHODIMP nsFontMetricsGTK::GetFontHandle(nsFontHandle &aHandle)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsFontGTK*
|
||||||
|
nsFontMetricsGTK::LocateFont(PRUint32 aChar, PRInt32 & aCount)
|
||||||
|
{
|
||||||
|
nsFontGTK *font;
|
||||||
|
PRInt32 i;
|
||||||
|
|
||||||
|
// see if one of our loaded fonts can represent the character
|
||||||
|
for (i = 0; i < aCount; ++i) {
|
||||||
|
font = (nsFontGTK*)mLoadedFonts[i];
|
||||||
|
if (CCMAP_HAS_CHAR(font->mCCMap, aChar))
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
font = FindFont(aChar);
|
||||||
|
aCount = mLoadedFontsCount; // update since FindFont() can change it
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsFontMetricsGTK::ResolveForwards(const PRUnichar *aString,
|
||||||
|
PRUint32 aLength,
|
||||||
|
nsFontSwitchCallbackGTK aFunc,
|
||||||
|
void *aData)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aString || !aLength, "invalid call");
|
||||||
|
const PRUnichar* firstChar = aString;
|
||||||
|
const PRUnichar* currChar = firstChar;
|
||||||
|
const PRUnichar* lastChar = aString + aLength;
|
||||||
|
nsFontGTK* currFont;
|
||||||
|
nsFontGTK* nextFont;
|
||||||
|
PRInt32 count;
|
||||||
|
nsFontSwitchGTK fontSwitch;
|
||||||
|
|
||||||
|
if (firstChar == lastChar)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
count = mLoadedFontsCount;
|
||||||
|
|
||||||
|
if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
|
||||||
|
currFont = LocateFont(SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
|
||||||
|
currChar += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currFont = LocateFont(*currChar, count);
|
||||||
|
++currChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
//This if block is meant to speedup the process in normal situation, when
|
||||||
|
//most characters can be found in first font
|
||||||
|
if (currFont == mLoadedFonts[0]) {
|
||||||
|
while (currChar < lastChar && CCMAP_HAS_CHAR(currFont->mCCMap,*currChar))
|
||||||
|
++currChar;
|
||||||
|
fontSwitch.mFontGTK = currFont;
|
||||||
|
if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
|
||||||
|
return NS_OK;
|
||||||
|
if (currChar == lastChar)
|
||||||
|
return NS_OK;
|
||||||
|
// continue with the next substring, re-using the available loaded fonts
|
||||||
|
firstChar = currChar;
|
||||||
|
if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
|
||||||
|
currFont = LocateFont(SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
|
||||||
|
currChar += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currFont = LocateFont(*currChar, count);
|
||||||
|
++currChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we can keep the same font for adjacent characters
|
||||||
|
PRInt32 lastCharLen;
|
||||||
|
while (currChar < lastChar) {
|
||||||
|
if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
|
||||||
|
nextFont = LocateFont(SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
|
||||||
|
lastCharLen = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nextFont = LocateFont(*currChar, count);
|
||||||
|
lastCharLen = 1;
|
||||||
|
}
|
||||||
|
if (nextFont != currFont) {
|
||||||
|
// We have a substring that can be represented with the same font, and
|
||||||
|
// we are about to switch fonts, it is time to notify our caller.
|
||||||
|
fontSwitch.mFontGTK = currFont;
|
||||||
|
if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
|
||||||
|
return NS_OK;
|
||||||
|
// continue with the next substring, re-using the available loaded fonts
|
||||||
|
firstChar = currChar;
|
||||||
|
|
||||||
|
currFont = nextFont; // use the font found earlier for the char
|
||||||
|
}
|
||||||
|
currChar += lastCharLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
//do it for last part of the string
|
||||||
|
fontSwitch.mFontGTK = currFont;
|
||||||
|
(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFontMetricsGTK::GetSpaceWidth(nscoord &aSpaceWidth)
|
nsFontMetricsGTK::GetSpaceWidth(nscoord &aSpaceWidth)
|
||||||
|
@ -264,6 +264,18 @@ protected:
|
|||||||
PRBool mAlreadyCalledLoadFont;
|
PRBool mAlreadyCalledLoadFont;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nsFontSwitchGTK {
|
||||||
|
// Simple wrapper on top of nsFontGTK for the moment
|
||||||
|
// Could hold other attributes of the font
|
||||||
|
nsFontGTK* mFontGTK;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef PRBool (*PR_CALLBACK nsFontSwitchCallbackGTK)
|
||||||
|
(const nsFontSwitchGTK *aFontSwitch,
|
||||||
|
const PRUnichar *aSubstring,
|
||||||
|
PRUint32 aSubstringLength,
|
||||||
|
void *aData);
|
||||||
|
|
||||||
class nsFontMetricsGTK : public nsIFontMetrics
|
class nsFontMetricsGTK : public nsIFontMetrics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -294,11 +306,14 @@ public:
|
|||||||
NS_IMETHOD GetMaxAscent(nscoord &aAscent);
|
NS_IMETHOD GetMaxAscent(nscoord &aAscent);
|
||||||
NS_IMETHOD GetMaxDescent(nscoord &aDescent);
|
NS_IMETHOD GetMaxDescent(nscoord &aDescent);
|
||||||
NS_IMETHOD GetMaxAdvance(nscoord &aAdvance);
|
NS_IMETHOD GetMaxAdvance(nscoord &aAdvance);
|
||||||
|
NS_IMETHOD GetAveCharWidth(nscoord &aAveCharWidth);
|
||||||
NS_IMETHOD GetFont(const nsFont *&aFont);
|
NS_IMETHOD GetFont(const nsFont *&aFont);
|
||||||
NS_IMETHOD GetLangGroup(nsIAtom** aLangGroup);
|
NS_IMETHOD GetLangGroup(nsIAtom** aLangGroup);
|
||||||
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle);
|
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle);
|
||||||
|
|
||||||
NS_IMETHOD GetSpaceWidth(nscoord &aSpaceWidth);
|
NS_IMETHOD GetSpaceWidth(nscoord &aSpaceWidth);
|
||||||
|
NS_IMETHOD ResolveForwards(const PRUnichar* aString, PRUint32 aLength,
|
||||||
|
nsFontSwitchCallbackGTK aFunc, void* aData);
|
||||||
|
|
||||||
nsFontGTK* FindFont(PRUnichar aChar);
|
nsFontGTK* FindFont(PRUnichar aChar);
|
||||||
nsFontGTK* FindUserDefinedFont(PRUnichar aChar);
|
nsFontGTK* FindUserDefinedFont(PRUnichar aChar);
|
||||||
@ -349,6 +364,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void RealizeFont();
|
void RealizeFont();
|
||||||
|
nsFontGTK* LocateFont(PRUint32 aChar, PRInt32 & aCount);
|
||||||
|
|
||||||
nsIDeviceContext *mDeviceContext;
|
nsIDeviceContext *mDeviceContext;
|
||||||
nsFont *mFont;
|
nsFont *mFont;
|
||||||
@ -370,6 +386,7 @@ protected:
|
|||||||
nscoord mUnderlineSize;
|
nscoord mUnderlineSize;
|
||||||
nscoord mUnderlineOffset;
|
nscoord mUnderlineOffset;
|
||||||
nscoord mSpaceWidth;
|
nscoord mSpaceWidth;
|
||||||
|
nscoord mAveCharWidth;
|
||||||
|
|
||||||
PRUint16 mPixelSize;
|
PRUint16 mPixelSize;
|
||||||
PRUint8 mStretchIndex;
|
PRUint8 mStretchIndex;
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
* the Initial Developer. All Rights Reserved.
|
* the Initial Developer. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
|
* Tomi Leppikangas <tomi.leppikangas@oulu.fi>
|
||||||
|
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
@ -47,6 +49,7 @@
|
|||||||
#include "nsGCCache.h"
|
#include "nsGCCache.h"
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include "prmem.h"
|
#include "prmem.h"
|
||||||
|
#include "prenv.h"
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GTK2
|
#ifdef MOZ_WIDGET_GTK2
|
||||||
#include <gdk/gdkwindow.h>
|
#include <gdk/gdkwindow.h>
|
||||||
@ -205,6 +208,50 @@ NS_IMETHODIMP nsRenderingContextGTK::GetHints(PRUint32& aResult)
|
|||||||
// XChar2b rendering. In addition, we can avoid the PRUnichar to
|
// XChar2b rendering. In addition, we can avoid the PRUnichar to
|
||||||
// XChar2b conversion. So we set this bit...
|
// XChar2b conversion. So we set this bit...
|
||||||
result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
|
result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
|
||||||
|
|
||||||
|
/* We can't enable fast text measuring (yet) on platforms
|
||||||
|
* which force natural alignment of datatypes (see
|
||||||
|
* http://bugzilla.mozilla.org/show_bug.cgi?id=36146#c46) ... ;-(
|
||||||
|
*/
|
||||||
|
#ifndef CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT
|
||||||
|
#if defined(__i386)
|
||||||
|
#define CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT 1
|
||||||
|
#endif /* __i386 */
|
||||||
|
#endif /* !CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT */
|
||||||
|
|
||||||
|
static PRBool enable_fast_measure;
|
||||||
|
static PRBool getenv_done = PR_FALSE;
|
||||||
|
|
||||||
|
/* Check for the env vars "MOZILLA_GFX_ENABLE_FAST_MEASURE" and
|
||||||
|
* "MOZILLA_GFX_DISABLE_FAST_MEASURE" to enable/disable fast text
|
||||||
|
* measuring (for debugging the feature and doing regression tests).
|
||||||
|
* This code will be removed one all issues around this new feature have
|
||||||
|
* been fixed. */
|
||||||
|
if (!getenv_done)
|
||||||
|
{
|
||||||
|
#ifdef CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT
|
||||||
|
enable_fast_measure = PR_TRUE;
|
||||||
|
#else
|
||||||
|
enable_fast_measure = PR_FALSE;
|
||||||
|
#endif /* CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT */
|
||||||
|
|
||||||
|
if (PR_GetEnv("MOZILLA_GFX_ENABLE_FAST_MEASURE"))
|
||||||
|
{
|
||||||
|
enable_fast_measure = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PR_GetEnv("MOZILLA_GFX_DISABLE_FAST_MEASURE"))
|
||||||
|
{
|
||||||
|
enable_fast_measure = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
getenv_done = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable_fast_measure) {
|
||||||
|
// We have GetTextDimensions()
|
||||||
|
result |= NS_RENDERING_HINT_FAST_MEASURE;
|
||||||
|
}
|
||||||
|
|
||||||
// XXX see if we are rendering to the local display or to a remote
|
// XXX see if we are rendering to the local display or to a remote
|
||||||
// dispaly and set the NS_RENDERING_HINT_REMOTE_RENDERING accordingly
|
// dispaly and set the NS_RENDERING_HINT_REMOTE_RENDERING accordingly
|
||||||
@ -1389,6 +1436,548 @@ FoundFont:
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsRenderingContextGTK::GetTextDimensions(const char* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
|
||||||
|
|
||||||
|
if (nsnull != mFontMetrics) {
|
||||||
|
// If we need to back up this state represents the last place we could
|
||||||
|
// break. We can use this to avoid remeasuring text
|
||||||
|
PRInt32 prevBreakState_BreakIndex = -1; // not known (hasn't been computed)
|
||||||
|
nscoord prevBreakState_Width = 0; // accumulated width to this point
|
||||||
|
|
||||||
|
// Initialize OUT parameters
|
||||||
|
mFontMetrics->GetMaxAscent(aLastWordDimensions.ascent);
|
||||||
|
mFontMetrics->GetMaxDescent(aLastWordDimensions.descent);
|
||||||
|
aLastWordDimensions.width = -1;
|
||||||
|
aNumCharsFit = 0;
|
||||||
|
|
||||||
|
// Iterate each character in the string and determine which font to use
|
||||||
|
nscoord width = 0;
|
||||||
|
PRInt32 start = 0;
|
||||||
|
nscoord aveCharWidth;
|
||||||
|
mFontMetrics->GetAveCharWidth(aveCharWidth);
|
||||||
|
|
||||||
|
while (start < aLength) {
|
||||||
|
// Estimate how many characters will fit. Do that by diving the available
|
||||||
|
// space by the average character width. Make sure the estimated number
|
||||||
|
// of characters is at least 1
|
||||||
|
PRInt32 estimatedNumChars = 0;
|
||||||
|
if (aveCharWidth > 0) {
|
||||||
|
estimatedNumChars = (aAvailWidth - width) / aveCharWidth;
|
||||||
|
}
|
||||||
|
if (estimatedNumChars < 1) {
|
||||||
|
estimatedNumChars = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the nearest break offset
|
||||||
|
PRInt32 estimatedBreakOffset = start + estimatedNumChars;
|
||||||
|
PRInt32 breakIndex;
|
||||||
|
nscoord numChars;
|
||||||
|
|
||||||
|
// Find the nearest place to break that is less than or equal to
|
||||||
|
// the estimated break offset
|
||||||
|
if (aLength <= estimatedBreakOffset) {
|
||||||
|
// All the characters should fit
|
||||||
|
numChars = aLength - start;
|
||||||
|
breakIndex = aNumBreaks - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
breakIndex = prevBreakState_BreakIndex;
|
||||||
|
while (((breakIndex + 1) < aNumBreaks) &&
|
||||||
|
(aBreaks[breakIndex + 1] <= estimatedBreakOffset)) {
|
||||||
|
++breakIndex;
|
||||||
|
}
|
||||||
|
if (breakIndex == prevBreakState_BreakIndex) {
|
||||||
|
++breakIndex; // make sure we advanced past the previous break index
|
||||||
|
}
|
||||||
|
numChars = aBreaks[breakIndex] - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure the text
|
||||||
|
nscoord twWidth = 0;
|
||||||
|
if ((1 == numChars) && (aString[start] == ' ')) {
|
||||||
|
mFontMetrics->GetSpaceWidth(twWidth);
|
||||||
|
}
|
||||||
|
else if (numChars > 0)
|
||||||
|
GetWidth( &aString[start], numChars, twWidth);
|
||||||
|
|
||||||
|
// See if the text fits
|
||||||
|
PRBool textFits = (twWidth + width) <= aAvailWidth;
|
||||||
|
|
||||||
|
// If the text fits then update the width and the number of
|
||||||
|
// characters that fit
|
||||||
|
if (textFits) {
|
||||||
|
aNumCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
start += numChars;
|
||||||
|
|
||||||
|
// This is a good spot to back up to if we need to so remember
|
||||||
|
// this state
|
||||||
|
prevBreakState_BreakIndex = breakIndex;
|
||||||
|
prevBreakState_Width = width;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// See if we can just back up to the previous saved state and not
|
||||||
|
// have to measure any text
|
||||||
|
if (prevBreakState_BreakIndex > 0) {
|
||||||
|
// If the previous break index is just before the current break index
|
||||||
|
// then we can use it
|
||||||
|
if (prevBreakState_BreakIndex == (breakIndex - 1)) {
|
||||||
|
aNumCharsFit = aBreaks[prevBreakState_BreakIndex];
|
||||||
|
width = prevBreakState_Width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't just revert to the previous break state
|
||||||
|
if (0 == breakIndex) {
|
||||||
|
// There's no place to back up to, so even though the text doesn't fit
|
||||||
|
// return it anyway
|
||||||
|
aNumCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeatedly back up until we get to where the text fits or we're all
|
||||||
|
// the way back to the first word
|
||||||
|
width += twWidth;
|
||||||
|
while ((breakIndex >= 1) && (width > aAvailWidth)) {
|
||||||
|
twWidth = 0;
|
||||||
|
start = aBreaks[breakIndex - 1];
|
||||||
|
numChars = aBreaks[breakIndex] - start;
|
||||||
|
|
||||||
|
if ((1 == numChars) && (aString[start] == ' ')) {
|
||||||
|
mFontMetrics->GetSpaceWidth(twWidth);
|
||||||
|
}
|
||||||
|
else if (numChars > 0)
|
||||||
|
GetWidth( &aString[start], numChars, twWidth);
|
||||||
|
|
||||||
|
width -= twWidth;
|
||||||
|
aNumCharsFit = start;
|
||||||
|
breakIndex--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aDimensions.width = width;
|
||||||
|
mFontMetrics->GetMaxAscent(aDimensions.ascent);
|
||||||
|
mFontMetrics->GetMaxDescent(aDimensions.descent);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BreakGetTextDimensionsData {
|
||||||
|
float mP2T; // IN
|
||||||
|
PRInt32 mAvailWidth; // IN
|
||||||
|
PRInt32* mBreaks; // IN
|
||||||
|
PRInt32 mNumBreaks; // IN
|
||||||
|
nscoord mSpaceWidth; // IN
|
||||||
|
nscoord mAveCharWidth; // IN
|
||||||
|
PRInt32 mEstimatedNumChars; // IN (running -- to handle the edge case of one word)
|
||||||
|
|
||||||
|
PRInt32 mNumCharsFit; // IN/OUT -- accumulated number of chars that fit so far
|
||||||
|
nscoord mWidth; // IN/OUT -- accumulated width so far
|
||||||
|
|
||||||
|
// If we need to back up, this state represents the last place
|
||||||
|
// we could break. We can use this to avoid remeasuring text
|
||||||
|
PRInt32 mPrevBreakState_BreakIndex; // IN/OUT, initialized as -1, i.e., not yet computed
|
||||||
|
nscoord mPrevBreakState_Width; // IN/OUT, initialized as 0
|
||||||
|
|
||||||
|
// Remember the fonts that we use so that we can deal with
|
||||||
|
// line-breaking in-between fonts later. mOffsets[0] is also used
|
||||||
|
// to initialize the current offset from where to start measuring
|
||||||
|
nsVoidArray* mFonts; // OUT
|
||||||
|
nsVoidArray* mOffsets; // IN/OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
static PRBool PR_CALLBACK
|
||||||
|
do_BreakGetTextDimensions(const nsFontSwitchGTK *aFontSwitch,
|
||||||
|
const PRUnichar* aSubstring,
|
||||||
|
PRUint32 aSubstringLength,
|
||||||
|
void* aData)
|
||||||
|
{
|
||||||
|
nsFontGTK* fontGTK = aFontSwitch->mFontGTK;
|
||||||
|
|
||||||
|
// Make sure the font is selected
|
||||||
|
BreakGetTextDimensionsData* data = (BreakGetTextDimensionsData*)aData;
|
||||||
|
|
||||||
|
// Our current state relative to the _full_ string...
|
||||||
|
// This allows emulation of the previous code...
|
||||||
|
const PRUnichar* pstr = (const PRUnichar*)data->mOffsets->ElementAt(0);
|
||||||
|
PRInt32 numCharsFit = data->mNumCharsFit;
|
||||||
|
nscoord width = data->mWidth;
|
||||||
|
PRInt32 start = (PRInt32)(aSubstring - pstr);
|
||||||
|
PRInt32 i = start + aSubstringLength;
|
||||||
|
PRBool allDone = PR_FALSE;
|
||||||
|
|
||||||
|
while (start < i) {
|
||||||
|
// Estimate how many characters will fit. Do that by dividing the
|
||||||
|
// available space by the average character width
|
||||||
|
PRInt32 estimatedNumChars = data->mEstimatedNumChars;
|
||||||
|
if (!estimatedNumChars && data->mAveCharWidth > 0) {
|
||||||
|
estimatedNumChars = (data->mAvailWidth - width) / data->mAveCharWidth;
|
||||||
|
}
|
||||||
|
// Make sure the estimated number of characters is at least 1
|
||||||
|
if (estimatedNumChars < 1) {
|
||||||
|
estimatedNumChars = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the nearest break offset
|
||||||
|
PRInt32 estimatedBreakOffset = start + estimatedNumChars;
|
||||||
|
PRInt32 breakIndex = -1; // not yet computed
|
||||||
|
PRBool inMiddleOfSegment = PR_FALSE;
|
||||||
|
nscoord numChars;
|
||||||
|
|
||||||
|
// Avoid scanning the break array in the case where we think all
|
||||||
|
// the text should fit
|
||||||
|
if (i <= estimatedBreakOffset) {
|
||||||
|
// Everything should fit
|
||||||
|
numChars = i - start;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Find the nearest place to break that is less than or equal to
|
||||||
|
// the estimated break offset
|
||||||
|
breakIndex = data->mPrevBreakState_BreakIndex;
|
||||||
|
while (data->mBreaks[breakIndex + 1] <= estimatedBreakOffset) {
|
||||||
|
++breakIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakIndex == -1)
|
||||||
|
breakIndex = 0;
|
||||||
|
|
||||||
|
// We found a place to break that is before the estimated break
|
||||||
|
// offset. Where we break depends on whether the text crosses a
|
||||||
|
// segment boundary
|
||||||
|
if (start < data->mBreaks[breakIndex]) {
|
||||||
|
// The text crosses at least one segment boundary so measure to the
|
||||||
|
// break point just before the estimated break offset
|
||||||
|
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// See whether there is another segment boundary between this one
|
||||||
|
// and the end of the text
|
||||||
|
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < i)) {
|
||||||
|
++breakIndex;
|
||||||
|
numChars = data->mBreaks[breakIndex] - start;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NS_ASSERTION(i != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
|
||||||
|
|
||||||
|
// The text is all within the same segment
|
||||||
|
numChars = i - start;
|
||||||
|
|
||||||
|
// Remember we're in the middle of a segment and not between
|
||||||
|
// two segments
|
||||||
|
inMiddleOfSegment = PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure the text
|
||||||
|
nscoord twWidth, pxWidth;
|
||||||
|
if ((1 == numChars) && (pstr[start] == ' ')) {
|
||||||
|
twWidth = data->mSpaceWidth;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pxWidth = fontGTK->GetWidth(&pstr[start], numChars);
|
||||||
|
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if the text fits
|
||||||
|
PRBool textFits = (twWidth + width) <= data->mAvailWidth;
|
||||||
|
|
||||||
|
// If the text fits then update the width and the number of
|
||||||
|
// characters that fit
|
||||||
|
if (textFits) {
|
||||||
|
numCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
|
||||||
|
// If we computed the break index and we're not in the middle
|
||||||
|
// of a segment then this is a spot that we can back up to if
|
||||||
|
// we need to, so remember this state
|
||||||
|
if ((breakIndex != -1) && !inMiddleOfSegment) {
|
||||||
|
data->mPrevBreakState_BreakIndex = breakIndex;
|
||||||
|
data->mPrevBreakState_Width = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The text didn't fit. If we're out of room then we're all done
|
||||||
|
allDone = PR_TRUE;
|
||||||
|
|
||||||
|
// See if we can just back up to the previous saved state and not
|
||||||
|
// have to measure any text
|
||||||
|
if (data->mPrevBreakState_BreakIndex != -1) {
|
||||||
|
PRBool canBackup;
|
||||||
|
|
||||||
|
// If we're in the middle of a word then the break index
|
||||||
|
// must be the same if we can use it. If we're at a segment
|
||||||
|
// boundary, then if the saved state is for the previous
|
||||||
|
// break index then we can use it
|
||||||
|
if (inMiddleOfSegment) {
|
||||||
|
canBackup = data->mPrevBreakState_BreakIndex == breakIndex;
|
||||||
|
} else {
|
||||||
|
canBackup = data->mPrevBreakState_BreakIndex == (breakIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canBackup) {
|
||||||
|
numCharsFit = data->mBreaks[data->mPrevBreakState_BreakIndex];
|
||||||
|
width = data->mPrevBreakState_Width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't just revert to the previous break state. Find the break
|
||||||
|
// index just before the end of the text
|
||||||
|
i = start + numChars;
|
||||||
|
if (breakIndex == -1) {
|
||||||
|
breakIndex = 0;
|
||||||
|
if (data->mBreaks[breakIndex] < i) {
|
||||||
|
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < i)) {
|
||||||
|
++breakIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
|
||||||
|
// There's no place to back up to, so even though the text doesn't fit
|
||||||
|
// return it anyway
|
||||||
|
numCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
|
||||||
|
// Edge case of one word: it could be that we just measured a fragment of the
|
||||||
|
// first word and its remainder involves other fonts, so we want to keep going
|
||||||
|
// until we at least measure the entire first word
|
||||||
|
if (numCharsFit < data->mBreaks[0]) {
|
||||||
|
allDone = PR_FALSE;
|
||||||
|
// From now on we don't care anymore what is the _real_ estimated
|
||||||
|
// number of characters that fits. Rather, we have no where to break
|
||||||
|
// and have to measure one word fully, but the real estimate is less
|
||||||
|
// than that one word. However, since the other bits of code rely on
|
||||||
|
// what is in "data->mEstimatedNumChars", we want to override
|
||||||
|
// "data->mEstimatedNumChars" and pass in what _has_ to be measured
|
||||||
|
// so that it is transparent to the other bits that depend on it.
|
||||||
|
data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
|
||||||
|
start += numChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeatedly back up until we get to where the text fits or we're
|
||||||
|
// all the way back to the first word
|
||||||
|
width += twWidth;
|
||||||
|
while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
|
||||||
|
twWidth = 0;
|
||||||
|
start = data->mBreaks[breakIndex];
|
||||||
|
numChars = i - start;
|
||||||
|
if ((1 == numChars) && (pstr[start] == ' ')) {
|
||||||
|
twWidth = data->mSpaceWidth;
|
||||||
|
}
|
||||||
|
else if (numChars > 0) {
|
||||||
|
pxWidth = fontGTK->GetWidth(&pstr[start], numChars);
|
||||||
|
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
|
||||||
|
}
|
||||||
|
|
||||||
|
width -= twWidth;
|
||||||
|
numCharsFit = start;
|
||||||
|
--breakIndex;
|
||||||
|
i = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start += numChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_rbs
|
||||||
|
NS_ASSERTION(allDone || start == i, "internal error");
|
||||||
|
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
|
||||||
|
#endif /* DEBUG_rbs */
|
||||||
|
|
||||||
|
if (data->mNumCharsFit != numCharsFit) {
|
||||||
|
// some text was actually retained
|
||||||
|
data->mWidth = width;
|
||||||
|
data->mNumCharsFit = numCharsFit;
|
||||||
|
data->mFonts->AppendElement(fontGTK);
|
||||||
|
data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allDone) {
|
||||||
|
// stop now
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_TRUE; // don't stop if we still need to measure more characters
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsRenderingContextGTK::GetTextDimensions(const PRUnichar* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID)
|
||||||
|
{
|
||||||
|
if (!mFontMetrics)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
nsFontMetricsGTK* metrics = (nsFontMetricsGTK*)mFontMetrics;
|
||||||
|
|
||||||
|
nscoord spaceWidth, aveCharWidth;
|
||||||
|
metrics->GetSpaceWidth(spaceWidth);
|
||||||
|
metrics->GetAveCharWidth(aveCharWidth);
|
||||||
|
|
||||||
|
// Note: aBreaks[] is supplied to us so that the first word is located
|
||||||
|
// at aString[0 .. aBreaks[0]-1] and more generally, the k-th word is
|
||||||
|
// located at aString[aBreaks[k-1] .. aBreaks[k]-1]. Whitespace can
|
||||||
|
// be included and each of them counts as a word in its own right.
|
||||||
|
|
||||||
|
// Upon completion of glyph resolution, characters that can be
|
||||||
|
// represented with fonts[i] are at offsets[i] .. offsets[i+1]-1
|
||||||
|
|
||||||
|
nsAutoVoidArray fonts, offsets;
|
||||||
|
offsets.AppendElement((void*)aString);
|
||||||
|
|
||||||
|
BreakGetTextDimensionsData data = { mP2T, aAvailWidth, aBreaks, aNumBreaks,
|
||||||
|
spaceWidth, aveCharWidth, 0, 0, 0, -1, 0, &fonts, &offsets
|
||||||
|
};
|
||||||
|
|
||||||
|
metrics->ResolveForwards(aString, aLength, do_BreakGetTextDimensions, &data);
|
||||||
|
|
||||||
|
if (aFontID) *aFontID = 0;
|
||||||
|
|
||||||
|
aNumCharsFit = data.mNumCharsFit;
|
||||||
|
aDimensions.width = data.mWidth;
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// Post-processing for the ascent and descent:
|
||||||
|
//
|
||||||
|
// The width of the last word is included in the final width, but its
|
||||||
|
// ascent and descent are kept aside for the moment. The problem is that
|
||||||
|
// line-breaking may occur _before_ the last word, and we don't want its
|
||||||
|
// ascent and descent to interfere. We can re-measure the last word and
|
||||||
|
// substract its width later. However, we need a special care for the ascent
|
||||||
|
// and descent at the break-point. The idea is to keep the ascent and descent
|
||||||
|
// of the last word separate, and let layout consider them later when it has
|
||||||
|
// determined that line-breaking doesn't occur before the last word.
|
||||||
|
//
|
||||||
|
// Therefore, there are two things to do:
|
||||||
|
// 1. Determine the ascent and descent up to where line-breaking may occur.
|
||||||
|
// 2. Determine the ascent and descent of the remainder.
|
||||||
|
// For efficiency however, it is okay to bail out early if there is only
|
||||||
|
// one font (in this case, the height of the last word has no special
|
||||||
|
// effect on the total height).
|
||||||
|
|
||||||
|
// aLastWordDimensions.width should be set to -1 to reply that we don't
|
||||||
|
// know the width of the last word since we measure multiple words
|
||||||
|
aLastWordDimensions.Clear();
|
||||||
|
aLastWordDimensions.width = -1;
|
||||||
|
|
||||||
|
PRInt32 count = fonts.Count();
|
||||||
|
if (!count)
|
||||||
|
return NS_OK;
|
||||||
|
nsFontGTK* fontGTK = (nsFontGTK*)fonts[0];
|
||||||
|
NS_ASSERTION(fontGTK, "internal error in do_BreakGetTextDimensions");
|
||||||
|
aDimensions.ascent = fontGTK->mMaxAscent;
|
||||||
|
aDimensions.descent = fontGTK->mMaxDescent;
|
||||||
|
|
||||||
|
// fast path - normal case, quick return if there is only one font
|
||||||
|
if (count == 1)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// get the last break index.
|
||||||
|
// If there is only one word, we end up with lastBreakIndex = 0. We don't
|
||||||
|
// need to worry about aLastWordDimensions in this case too. But if we didn't
|
||||||
|
// return earlier, it would mean that the unique word needs several fonts
|
||||||
|
// and we will still have to loop over the fonts to return the final height
|
||||||
|
PRInt32 lastBreakIndex = 0;
|
||||||
|
while (aBreaks[lastBreakIndex] < aNumCharsFit)
|
||||||
|
++lastBreakIndex;
|
||||||
|
|
||||||
|
const PRUnichar* lastWord = (lastBreakIndex > 0)
|
||||||
|
? aString + aBreaks[lastBreakIndex-1]
|
||||||
|
: aString + aNumCharsFit; // let it point outside to play nice with the loop
|
||||||
|
|
||||||
|
// now get the desired ascent and descent information... this is however
|
||||||
|
// a very fast loop of the order of the number of additional fonts
|
||||||
|
|
||||||
|
PRInt32 currFont = 0;
|
||||||
|
const PRUnichar* pstr = aString;
|
||||||
|
const PRUnichar* last = aString + aNumCharsFit;
|
||||||
|
|
||||||
|
while (pstr < last) {
|
||||||
|
fontGTK = (nsFontGTK*)fonts[currFont];
|
||||||
|
PRUnichar* nextOffset = (PRUnichar*)offsets[++currFont];
|
||||||
|
|
||||||
|
// For consistent word-wrapping, we are going to handle the whitespace
|
||||||
|
// character with special care because a whitespace character can come
|
||||||
|
// from a font different from that of the previous word. If 'x', 'y', 'z',
|
||||||
|
// are Unicode points that require different fonts, we want 'xyz <br>'
|
||||||
|
// and 'xyz<br>' to have the same height because it gives a more stable
|
||||||
|
// rendering, especially when the window is resized at the edge of the word.
|
||||||
|
// If we don't do this, a 'tall' trailing whitespace, i.e., if the whitespace
|
||||||
|
// happens to come from a font with a bigger ascent and/or descent than all
|
||||||
|
// current fonts on the line, this can cause the next lines to be shifted
|
||||||
|
// down when the window is slowly resized to fit that whitespace.
|
||||||
|
if (*pstr == ' ') {
|
||||||
|
// skip pass the whitespace to ignore the height that it may contribute
|
||||||
|
++pstr;
|
||||||
|
// get out if we reached the end
|
||||||
|
if (pstr == last) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// switch to the next font if we just passed the current font
|
||||||
|
if (pstr == nextOffset) {
|
||||||
|
fontGTK = (nsFontGTK*)fonts[currFont];
|
||||||
|
nextOffset = (PRUnichar*)offsets[++currFont];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if the last word intersects with the current font
|
||||||
|
// (we are testing for 'nextOffset-1 >= lastWord' since the
|
||||||
|
// current font ends at nextOffset-1)
|
||||||
|
if (nextOffset > lastWord) {
|
||||||
|
if (aLastWordDimensions.ascent < fontGTK->mMaxAscent) {
|
||||||
|
aLastWordDimensions.ascent = fontGTK->mMaxAscent;
|
||||||
|
}
|
||||||
|
if (aLastWordDimensions.descent < fontGTK->mMaxDescent) {
|
||||||
|
aLastWordDimensions.descent = fontGTK->mMaxDescent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we have not reached the last word yet
|
||||||
|
if (pstr < lastWord) {
|
||||||
|
if (aDimensions.ascent < fontGTK->mMaxAscent) {
|
||||||
|
aDimensions.ascent = fontGTK->mMaxAscent;
|
||||||
|
}
|
||||||
|
if (aDimensions.descent < fontGTK->mMaxDescent) {
|
||||||
|
aDimensions.descent = fontGTK->mMaxDescent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// advance to where the next font starts
|
||||||
|
pstr = nextOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsRenderingContextGTK::GetTextDimensions(const char* aString, PRUint32 aLength,
|
nsRenderingContextGTK::GetTextDimensions(const char* aString, PRUint32 aLength,
|
||||||
nsTextDimensions& aDimensions)
|
nsTextDimensions& aDimensions)
|
||||||
@ -1572,7 +2161,7 @@ nsRenderingContextGTK::DrawString(const char *aString, PRUint32 aLength,
|
|||||||
{
|
{
|
||||||
nscoord height;
|
nscoord height;
|
||||||
|
|
||||||
mFontMetrics->GetHeight(height);
|
mFontMetrics->GetHeight(height);
|
||||||
|
|
||||||
DrawLine(aX, aY + (height >> 1), aX + aWidth, aY + (height >> 1));
|
DrawLine(aX, aY + (height >> 1), aX + aWidth, aY + (height >> 1));
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,24 @@ public:
|
|||||||
nsTextDimensions& aDimensions);
|
nsTextDimensions& aDimensions);
|
||||||
NS_IMETHOD GetTextDimensions(const PRUnichar *aString, PRUint32 aLength,
|
NS_IMETHOD GetTextDimensions(const PRUnichar *aString, PRUint32 aLength,
|
||||||
nsTextDimensions& aDimensions, PRInt32 *aFontID);
|
nsTextDimensions& aDimensions, PRInt32 *aFontID);
|
||||||
|
NS_IMETHOD GetTextDimensions(const char* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID = nsnull);
|
||||||
|
NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID = nsnull);
|
||||||
|
|
||||||
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY);
|
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY);
|
||||||
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY,
|
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY,
|
||||||
|
@ -395,8 +395,11 @@ nsRenderingContextOS2::GetDrawingSurface( nsDrawingSurface *aSurface)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsRenderingContextOS2::GetHints(PRUint32& aResult)
|
nsRenderingContextOS2::GetHints(PRUint32& aResult)
|
||||||
{
|
{
|
||||||
aResult = 0;
|
PRUint32 result = 0;
|
||||||
|
|
||||||
|
result |= NS_RENDERING_HINT_FAST_MEASURE;
|
||||||
|
|
||||||
|
aResult = result;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1790,7 +1793,13 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
|
|||||||
// until we at least measure the first word entirely
|
// until we at least measure the first word entirely
|
||||||
if (numCharsFit < data->mBreaks[0]) {
|
if (numCharsFit < data->mBreaks[0]) {
|
||||||
allDone = PR_FALSE;
|
allDone = PR_FALSE;
|
||||||
// from now on, the estimated number of characters is what we want to measure
|
// From now on we don't care anymore what is the _real_ estimated
|
||||||
|
// number of characters that fits. Rather, we have no where to break
|
||||||
|
// and have to measure one word fully, but the real estimate is less
|
||||||
|
// than that one word. However, since the other bits of code rely on
|
||||||
|
// what is in "data->mEstimatedNumChars", we want to override
|
||||||
|
// "data->mEstimatedNumChars" and pass in what _has_ to be measured
|
||||||
|
// so that it is transparent to the other bits that depend on it.
|
||||||
data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
|
data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
|
||||||
start += numChars;
|
start += numChars;
|
||||||
}
|
}
|
||||||
@ -1980,7 +1989,7 @@ nsRenderingContextOS2::GetTextDimensions(const PRUnichar* aString,
|
|||||||
// If we don't do this, a 'tall' trailing whitespace, i.e., if the whitespace
|
// If we don't do this, a 'tall' trailing whitespace, i.e., if the whitespace
|
||||||
// happens to come from a font with a bigger ascent and/or descent than all
|
// happens to come from a font with a bigger ascent and/or descent than all
|
||||||
// current fonts on the line, this can cause the next lines to be shifted
|
// current fonts on the line, this can cause the next lines to be shifted
|
||||||
// down the window is slowly resized to fit that whitespace.
|
// down when the window is slowly resized to fit that whitespace.
|
||||||
if (*pstr == ' ') {
|
if (*pstr == ' ') {
|
||||||
// skip pass the whitespace to ignore the height that it may contribute
|
// skip pass the whitespace to ignore the height that it may contribute
|
||||||
++pstr;
|
++pstr;
|
||||||
|
@ -167,7 +167,9 @@ float offset;
|
|||||||
mMaxDescent = mDescent;
|
mMaxDescent = mDescent;
|
||||||
mMaxAdvance = mHeight;
|
mMaxAdvance = mHeight;
|
||||||
|
|
||||||
GetStringWidth(" ", mSpaceWidth, 1);
|
GetStringWidth(" ", mSpaceWidth, 1);
|
||||||
|
GetStringWidth("x", mAveCharWidth, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ---------------------------------------------------
|
/** ---------------------------------------------------
|
||||||
@ -332,6 +334,13 @@ nsFontMetricsPS :: GetMaxAdvance(nscoord &aAdvance)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsFontMetricsPS :: GetAveCharWidth(nscoord &aAveCharWidth)
|
||||||
|
{
|
||||||
|
aAveCharWidth = mAveCharWidth;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/** ---------------------------------------------------
|
/** ---------------------------------------------------
|
||||||
* See documentation in nsFontMetricsPS.h
|
* See documentation in nsFontMetricsPS.h
|
||||||
* @update 2/26/99 dwc
|
* @update 2/26/99 dwc
|
||||||
|
@ -81,6 +81,7 @@ public:
|
|||||||
NS_IMETHOD GetMaxAscent(nscoord &aAscent);
|
NS_IMETHOD GetMaxAscent(nscoord &aAscent);
|
||||||
NS_IMETHOD GetMaxDescent(nscoord &aDescent);
|
NS_IMETHOD GetMaxDescent(nscoord &aDescent);
|
||||||
NS_IMETHOD GetMaxAdvance(nscoord &aAdvance);
|
NS_IMETHOD GetMaxAdvance(nscoord &aAdvance);
|
||||||
|
NS_IMETHOD GetAveCharWidth(nscoord &aAveCharWidth);
|
||||||
NS_IMETHOD GetSpaceWidth(nscoord& aAveCharWidth);
|
NS_IMETHOD GetSpaceWidth(nscoord& aAveCharWidth);
|
||||||
NS_IMETHOD GetFont(const nsFont *&aFont);
|
NS_IMETHOD GetFont(const nsFont *&aFont);
|
||||||
NS_IMETHOD GetLangGroup(nsIAtom** aLangGroup);
|
NS_IMETHOD GetLangGroup(nsIAtom** aLangGroup);
|
||||||
@ -128,6 +129,7 @@ protected:
|
|||||||
nscoord mUnderlineSize;
|
nscoord mUnderlineSize;
|
||||||
nscoord mUnderlineOffset;
|
nscoord mUnderlineOffset;
|
||||||
nscoord mSpaceWidth;
|
nscoord mSpaceWidth;
|
||||||
|
nscoord mAveCharWidth;
|
||||||
PRInt16 mFontIndex;
|
PRInt16 mFontIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1023,6 +1023,35 @@ nsRenderingContextPS :: GetWidth(const PRUnichar *aString,PRUint32 aLength,nscoo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** --------------------------------------------------- */
|
/** --------------------------------------------------- */
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsRenderingContextPS::GetTextDimensions(const char* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID)
|
||||||
|
{
|
||||||
|
NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsRenderingContextPS::GetTextDimensions(const PRUnichar* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID)
|
||||||
|
{
|
||||||
|
NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsRenderingContextPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
|
nsRenderingContextPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
|
||||||
|
@ -170,6 +170,24 @@ public:
|
|||||||
nsTextDimensions& aDimensions);
|
nsTextDimensions& aDimensions);
|
||||||
NS_IMETHOD GetTextDimensions(const PRUnichar *aString, PRUint32 aLength,
|
NS_IMETHOD GetTextDimensions(const PRUnichar *aString, PRUint32 aLength,
|
||||||
nsTextDimensions& aDimensions, PRInt32 *aFontID);
|
nsTextDimensions& aDimensions, PRInt32 *aFontID);
|
||||||
|
NS_IMETHOD GetTextDimensions(const char* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID = nsnull);
|
||||||
|
NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID = nsnull);
|
||||||
|
|
||||||
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY);
|
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY);
|
||||||
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY,
|
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY,
|
||||||
|
@ -3573,7 +3573,7 @@ nsFontMetricsWin::ResolveForwards(HDC aDC,
|
|||||||
++currChar;
|
++currChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
//This if block is mean to speedup the process in normal situation, when
|
//This if block is meant to speedup the process in normal situation, when
|
||||||
//most characters can be found in first font
|
//most characters can be found in first font
|
||||||
if (currFont == mLoadedFonts[0]) {
|
if (currFont == mLoadedFonts[0]) {
|
||||||
while (currChar < lastChar && (currFont->HasGlyph(*currChar)))
|
while (currChar < lastChar && (currFont->HasGlyph(*currChar)))
|
||||||
@ -5024,7 +5024,7 @@ nsFontMetricsWinA::ResolveForwards(HDC aDC,
|
|||||||
count = mLoadedFonts.Count();
|
count = mLoadedFonts.Count();
|
||||||
currSubset = LocateFontSubset(aDC, *currChar, count, currFont);
|
currSubset = LocateFontSubset(aDC, *currChar, count, currFont);
|
||||||
|
|
||||||
//This if block is mean to speedup the process in normal situation, when
|
//This if block is meant to speedup the process in normal situation, when
|
||||||
//most characters can be found in first font
|
//most characters can be found in first font
|
||||||
if (currFont == mLoadedFonts[0]) {
|
if (currFont == mLoadedFonts[0]) {
|
||||||
while (++currChar < lastChar && currFont->HasGlyph(*(currChar)) && currSubset->HasGlyph(*currChar)) ;
|
while (++currChar < lastChar && currFont->HasGlyph(*(currChar)) && currSubset->HasGlyph(*currChar)) ;
|
||||||
|
@ -639,6 +639,8 @@ NS_IMETHODIMP
|
|||||||
nsRenderingContextWin :: GetHints(PRUint32& aResult)
|
nsRenderingContextWin :: GetHints(PRUint32& aResult)
|
||||||
{
|
{
|
||||||
PRUint32 result = 0;
|
PRUint32 result = 0;
|
||||||
|
|
||||||
|
result |= NS_RENDERING_HINT_FAST_MEASURE;
|
||||||
|
|
||||||
if (gIsWIN95)
|
if (gIsWIN95)
|
||||||
result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
|
result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
|
||||||
@ -1704,7 +1706,7 @@ nsRenderingContextWin::GetTextDimensions(const char* aString,
|
|||||||
|
|
||||||
// We can't just revert to the previous break state
|
// We can't just revert to the previous break state
|
||||||
if (0 == breakIndex) {
|
if (0 == breakIndex) {
|
||||||
// There's no place to back up to so even though the text doesn't fit
|
// There's no place to back up to, so even though the text doesn't fit
|
||||||
// return it anyway
|
// return it anyway
|
||||||
aNumCharsFit += numChars;
|
aNumCharsFit += numChars;
|
||||||
width += twWidth;
|
width += twWidth;
|
||||||
@ -1788,8 +1790,8 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
|
|||||||
::SelectObject(data->mDC, data->mFont);
|
::SelectObject(data->mDC, data->mFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our current state relatively to the _full_ string...
|
// Our current state relative to the _full_ string...
|
||||||
// This allows emulating the previous code...
|
// This allows emulation of the previous code...
|
||||||
const PRUnichar* pstr = (const PRUnichar*)data->mOffsets->ElementAt(0);
|
const PRUnichar* pstr = (const PRUnichar*)data->mOffsets->ElementAt(0);
|
||||||
PRInt32 numCharsFit = data->mNumCharsFit;
|
PRInt32 numCharsFit = data->mNumCharsFit;
|
||||||
nscoord width = data->mWidth;
|
nscoord width = data->mWidth;
|
||||||
@ -1853,7 +1855,7 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
|
|||||||
// The text is all within the same segment
|
// The text is all within the same segment
|
||||||
numChars = i - start;
|
numChars = i - start;
|
||||||
|
|
||||||
// Remember we're in the middle of a segment and not in between
|
// Remember we're in the middle of a segment and not between
|
||||||
// two segments
|
// two segments
|
||||||
inMiddleOfSegment = PR_TRUE;
|
inMiddleOfSegment = PR_TRUE;
|
||||||
}
|
}
|
||||||
@ -1881,7 +1883,7 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
|
|||||||
|
|
||||||
// If we computed the break index and we're not in the middle
|
// If we computed the break index and we're not in the middle
|
||||||
// of a segment then this is a spot that we can back up to if
|
// of a segment then this is a spot that we can back up to if
|
||||||
// we need to so remember this state
|
// we need to, so remember this state
|
||||||
if ((breakIndex != -1) && !inMiddleOfSegment) {
|
if ((breakIndex != -1) && !inMiddleOfSegment) {
|
||||||
data->mPrevBreakState_BreakIndex = breakIndex;
|
data->mPrevBreakState_BreakIndex = breakIndex;
|
||||||
data->mPrevBreakState_Width = width;
|
data->mPrevBreakState_Width = width;
|
||||||
@ -1926,17 +1928,23 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
|
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
|
||||||
// There's no place to back up to so even though the text doesn't fit
|
// There's no place to back up to, so even though the text doesn't fit
|
||||||
// return it anyway
|
// return it anyway
|
||||||
numCharsFit += numChars;
|
numCharsFit += numChars;
|
||||||
width += twWidth;
|
width += twWidth;
|
||||||
|
|
||||||
// Edge case of one word: it could be that we just measured a fragment of the
|
// Edge case of one word: it could be that we just measured a fragment of the
|
||||||
// first word and its remainder involves other fonts, so we want to keep going
|
// first word and its remainder involves other fonts, so we want to keep going
|
||||||
// until we at least measure the first word entirely
|
// until we at least measure the entire first word
|
||||||
if (numCharsFit < data->mBreaks[0]) {
|
if (numCharsFit < data->mBreaks[0]) {
|
||||||
allDone = PR_FALSE;
|
allDone = PR_FALSE;
|
||||||
// from now on, the estimated number of characters is what we want to measure
|
// From now on we don't care anymore what is the _real_ estimated
|
||||||
|
// number of characters that fits. Rather, we have no where to break
|
||||||
|
// and have to measure one word fully, but the real estimate is less
|
||||||
|
// than that one word. However, since the other bits of code rely on
|
||||||
|
// what is in "data->mEstimatedNumChars", we want to override
|
||||||
|
// "data->mEstimatedNumChars" and pass in what _has_ to be measured
|
||||||
|
// so that it is transparent to the other bits that depend on it.
|
||||||
data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
|
data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
|
||||||
start += numChars;
|
start += numChars;
|
||||||
}
|
}
|
||||||
@ -1972,7 +1980,7 @@ do_BreakGetTextDimensions(const nsFontSwitch* aFontSwitch,
|
|||||||
#ifdef DEBUG_rbs
|
#ifdef DEBUG_rbs
|
||||||
NS_ASSERTION(allDone || start == i, "internal error");
|
NS_ASSERTION(allDone || start == i, "internal error");
|
||||||
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
|
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
|
||||||
#endif
|
#endif /* DEBUG_rbs */
|
||||||
|
|
||||||
if (data->mNumCharsFit != numCharsFit) {
|
if (data->mNumCharsFit != numCharsFit) {
|
||||||
// some text was actually retained
|
// some text was actually retained
|
||||||
@ -2108,7 +2116,7 @@ nsRenderingContextWin::GetTextDimensions(const PRUnichar* aString,
|
|||||||
// If we don't do this, a 'tall' trailing whitespace, i.e., if the whitespace
|
// If we don't do this, a 'tall' trailing whitespace, i.e., if the whitespace
|
||||||
// happens to come from a font with a bigger ascent and/or descent than all
|
// happens to come from a font with a bigger ascent and/or descent than all
|
||||||
// current fonts on the line, this can cause the next lines to be shifted
|
// current fonts on the line, this can cause the next lines to be shifted
|
||||||
// down the window is slowly resized to fit that whitespace.
|
// down when the window is slowly resized to fit that whitespace.
|
||||||
if (*pstr == ' ') {
|
if (*pstr == ' ') {
|
||||||
// skip pass the whitespace to ignore the height that it may contribute
|
// skip pass the whitespace to ignore the height that it may contribute
|
||||||
++pstr;
|
++pstr;
|
||||||
@ -2135,7 +2143,7 @@ nsRenderingContextWin::GetTextDimensions(const PRUnichar* aString,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// see we have not reached the last word yet
|
// see if we have not reached the last word yet
|
||||||
if (pstr < lastWord) {
|
if (pstr < lastWord) {
|
||||||
if (aDimensions.ascent < fontWin->mMaxAscent) {
|
if (aDimensions.ascent < fontWin->mMaxAscent) {
|
||||||
aDimensions.ascent = fontWin->mMaxAscent;
|
aDimensions.ascent = fontWin->mMaxAscent;
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
#include "xprintutil.h"
|
#include "xprintutil.h"
|
||||||
#endif /* USE_XPRINT */
|
#endif /* USE_XPRINT */
|
||||||
#include "xlibrgb.h"
|
#include "xlibrgb.h"
|
||||||
|
#include "nsUnicharUtils.h"
|
||||||
#ifdef ENABLE_X_FONT_BANNING
|
#ifdef ENABLE_X_FONT_BANNING
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#endif /* ENABLE_X_FONT_BANNING */
|
#endif /* ENABLE_X_FONT_BANNING */
|
||||||
@ -1654,6 +1655,9 @@ void nsFontMetricsXlib::RealizeFont()
|
|||||||
PRUnichar space = (PRUnichar)' ';
|
PRUnichar space = (PRUnichar)' ';
|
||||||
mSpaceWidth = NSToCoordRound(ft->GetWidth(&space, 1) * f);
|
mSpaceWidth = NSToCoordRound(ft->GetWidth(&space, 1) * f);
|
||||||
|
|
||||||
|
PRUnichar averageX = (PRUnichar)'x';
|
||||||
|
mAveCharWidth = NSToCoordRound(ft->GetWidth(&averageX, 1) * f);
|
||||||
|
|
||||||
unsigned long pr = 0;
|
unsigned long pr = 0;
|
||||||
if (ft->getXHeight(pr)) {
|
if (ft->getXHeight(pr)) {
|
||||||
mXHeight = nscoord(pr * f);
|
mXHeight = nscoord(pr * f);
|
||||||
@ -1723,17 +1727,22 @@ void nsFontMetricsXlib::RealizeFont()
|
|||||||
|
|
||||||
mMaxAdvance = nscoord(fontInfo->max_bounds.width * f);
|
mMaxAdvance = nscoord(fontInfo->max_bounds.width * f);
|
||||||
|
|
||||||
int rawWidth;
|
int rawWidth, rawAverage;
|
||||||
if ((fontInfo->min_byte1 == 0) && (fontInfo->max_byte1 == 0)) {
|
if ((fontInfo->min_byte1 == 0) && (fontInfo->max_byte1 == 0)) {
|
||||||
rawWidth = xFont->TextWidth8(" ", 1);
|
rawWidth = xFont->TextWidth8(" ", 1);
|
||||||
|
rawAverage = xFont->TextWidth8("x", 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
XChar2b my16bit_space;
|
XChar2b my16bit_space, my16bit_x;
|
||||||
my16bit_space.byte1 = '\0';
|
my16bit_space.byte1 = '\0';
|
||||||
my16bit_space.byte2 = ' ';
|
my16bit_space.byte2 = ' ';
|
||||||
rawWidth = xFont->TextWidth16(&my16bit_space, 1);
|
my16bit_x.byte1 = 0;
|
||||||
|
my16bit_x.byte2 = 'x';
|
||||||
|
rawWidth = xFont->TextWidth16(&my16bit_space, 1);
|
||||||
|
rawAverage = xFont->TextWidth16(&my16bit_x, 1);
|
||||||
}
|
}
|
||||||
mSpaceWidth = NSToCoordRound(rawWidth * f);
|
mSpaceWidth = NSToCoordRound(rawWidth * f);
|
||||||
|
mAveCharWidth = NSToCoordRound(rawAverage * f);
|
||||||
|
|
||||||
unsigned long pr = 0;
|
unsigned long pr = 0;
|
||||||
if (xFont->GetXFontProperty(XA_X_HEIGHT, &pr) &&
|
if (xFont->GetXFontProperty(XA_X_HEIGHT, &pr) &&
|
||||||
@ -1903,6 +1912,13 @@ NS_IMETHODIMP nsFontMetricsXlib::GetMaxAdvance(nscoord &aAdvance)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsFontMetricsXlib::GetAveCharWidth(nscoord &aAveCharWidth)
|
||||||
|
{
|
||||||
|
aAveCharWidth = mAveCharWidth;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP nsFontMetricsXlib::GetFont(const nsFont*& aFont)
|
NS_IMETHODIMP nsFontMetricsXlib::GetFont(const nsFont*& aFont)
|
||||||
{
|
{
|
||||||
aFont = mFont;
|
aFont = mFont;
|
||||||
@ -1927,6 +1943,106 @@ NS_IMETHODIMP nsFontMetricsXlib::GetFontHandle(nsFontHandle &aHandle)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsFontXlib*
|
||||||
|
nsFontMetricsXlib::LocateFont(PRUint32 aChar, PRInt32 & aCount)
|
||||||
|
{
|
||||||
|
nsFontXlib *font;
|
||||||
|
PRInt32 i;
|
||||||
|
|
||||||
|
// see if one of our loaded fonts can represent the character
|
||||||
|
for (i = 0; i < aCount; ++i) {
|
||||||
|
font = (nsFontXlib *)mLoadedFonts[i];
|
||||||
|
if (CCMAP_HAS_CHAR(font->mCCMap, aChar))
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
font = FindFont(aChar);
|
||||||
|
aCount = mLoadedFontsCount; // update since FindFont() can change it
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsFontMetricsXlib::ResolveForwards(const PRUnichar* aString,
|
||||||
|
PRUint32 aLength,
|
||||||
|
nsFontSwitchCallbackXlib aFunc,
|
||||||
|
void* aData)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aString || !aLength, "invalid call");
|
||||||
|
const PRUnichar* firstChar = aString;
|
||||||
|
const PRUnichar* currChar = firstChar;
|
||||||
|
const PRUnichar* lastChar = aString + aLength;
|
||||||
|
nsFontXlib* currFont;
|
||||||
|
nsFontXlib* nextFont;
|
||||||
|
PRInt32 count;
|
||||||
|
nsFontSwitchXlib fontSwitch;
|
||||||
|
|
||||||
|
if (firstChar == lastChar)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
count = mLoadedFontsCount;
|
||||||
|
|
||||||
|
if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
|
||||||
|
currFont = LocateFont(SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
|
||||||
|
currChar += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currFont = LocateFont(*currChar, count);
|
||||||
|
++currChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
//This if block is meant to speedup the process in normal situation, when
|
||||||
|
//most characters can be found in first font
|
||||||
|
if (currFont == mLoadedFonts[0]) {
|
||||||
|
while (currChar < lastChar && CCMAP_HAS_CHAR(currFont->mCCMap,*currChar))
|
||||||
|
++currChar;
|
||||||
|
fontSwitch.mFontXlib = currFont;
|
||||||
|
if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
|
||||||
|
return NS_OK;
|
||||||
|
if (currChar == lastChar)
|
||||||
|
return NS_OK;
|
||||||
|
// continue with the next substring, re-using the available loaded fonts
|
||||||
|
firstChar = currChar;
|
||||||
|
if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
|
||||||
|
currFont = LocateFont(SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
|
||||||
|
currChar += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currFont = LocateFont(*currChar, count);
|
||||||
|
++currChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we can keep the same font for adjacent characters
|
||||||
|
PRInt32 lastCharLen;
|
||||||
|
while (currChar < lastChar) {
|
||||||
|
if (IS_HIGH_SURROGATE(*currChar) && (currChar+1) < lastChar && IS_LOW_SURROGATE(*(currChar+1))) {
|
||||||
|
nextFont = LocateFont(SURROGATE_TO_UCS4(*currChar, *(currChar+1)), count);
|
||||||
|
lastCharLen = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nextFont = LocateFont(*currChar, count);
|
||||||
|
lastCharLen = 1;
|
||||||
|
}
|
||||||
|
if (nextFont != currFont) {
|
||||||
|
// We have a substring that can be represented with the same font, and
|
||||||
|
// we are about to switch fonts, it is time to notify our caller.
|
||||||
|
fontSwitch.mFontXlib = currFont;
|
||||||
|
if (!(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData))
|
||||||
|
return NS_OK;
|
||||||
|
// continue with the next substring, re-using the available loaded fonts
|
||||||
|
firstChar = currChar;
|
||||||
|
|
||||||
|
currFont = nextFont; // use the font found earlier for the char
|
||||||
|
}
|
||||||
|
currChar += lastCharLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
//do it for last part of the string
|
||||||
|
fontSwitch.mFontXlib = currFont;
|
||||||
|
(*aFunc)(&fontSwitch, firstChar, currChar - firstChar, aData);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFontMetricsXlib::GetSpaceWidth(nscoord &aSpaceWidth)
|
nsFontMetricsXlib::GetSpaceWidth(nscoord &aSpaceWidth)
|
||||||
|
@ -339,6 +339,18 @@ protected:
|
|||||||
PRPackedBool mAlreadyCalledLoadFont;
|
PRPackedBool mAlreadyCalledLoadFont;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nsFontSwitchXlib {
|
||||||
|
// Simple wrapper on top of nsFontXlib for the moment
|
||||||
|
// Could hold other attributes of the font
|
||||||
|
nsFontXlib *mFontXlib;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef PRBool (*PR_CALLBACK nsFontSwitchCallbackXlib)
|
||||||
|
(const nsFontSwitchXlib *aFontSwitch,
|
||||||
|
const PRUnichar* aSubstring,
|
||||||
|
PRUint32 aSubstringLength,
|
||||||
|
void* aData);
|
||||||
|
|
||||||
class nsFontMetricsXlib : public nsIFontMetrics
|
class nsFontMetricsXlib : public nsIFontMetrics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -376,12 +388,14 @@ public:
|
|||||||
NS_IMETHOD GetMaxAscent(nscoord &aAscent);
|
NS_IMETHOD GetMaxAscent(nscoord &aAscent);
|
||||||
NS_IMETHOD GetMaxDescent(nscoord &aDescent);
|
NS_IMETHOD GetMaxDescent(nscoord &aDescent);
|
||||||
NS_IMETHOD GetMaxAdvance(nscoord &aAdvance);
|
NS_IMETHOD GetMaxAdvance(nscoord &aAdvance);
|
||||||
|
NS_IMETHOD GetAveCharWidth(nscoord &aAveCharWidth);
|
||||||
NS_IMETHOD GetFont(const nsFont *&aFont);
|
NS_IMETHOD GetFont(const nsFont *&aFont);
|
||||||
NS_IMETHOD GetLangGroup(nsIAtom** aLangGroup);
|
NS_IMETHOD GetLangGroup(nsIAtom** aLangGroup);
|
||||||
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle);
|
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle);
|
||||||
|
|
||||||
NS_IMETHOD GetSpaceWidth(nscoord &aSpaceWidth);
|
NS_IMETHOD GetSpaceWidth(nscoord &aSpaceWidth);
|
||||||
|
NS_IMETHOD ResolveForwards(const PRUnichar* aString, PRUint32 aLength,
|
||||||
|
nsFontSwitchCallbackXlib aFunc, void* aData);
|
||||||
nsFontXlib* FindFont(PRUnichar aChar);
|
nsFontXlib* FindFont(PRUnichar aChar);
|
||||||
nsFontXlib* FindUserDefinedFont(PRUnichar aChar);
|
nsFontXlib* FindUserDefinedFont(PRUnichar aChar);
|
||||||
nsFontXlib* FindStyleSheetSpecificFont(PRUnichar aChar);
|
nsFontXlib* FindStyleSheetSpecificFont(PRUnichar aChar);
|
||||||
@ -433,6 +447,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void RealizeFont();
|
void RealizeFont();
|
||||||
|
nsFontXlib *LocateFont(PRUint32 aChar, PRInt32 & aCount);
|
||||||
|
|
||||||
nsIDeviceContext *mDeviceContext;
|
nsIDeviceContext *mDeviceContext;
|
||||||
nsFont *mFont;
|
nsFont *mFont;
|
||||||
@ -454,6 +469,7 @@ protected:
|
|||||||
nscoord mUnderlineSize;
|
nscoord mUnderlineSize;
|
||||||
nscoord mUnderlineOffset;
|
nscoord mUnderlineOffset;
|
||||||
nscoord mSpaceWidth;
|
nscoord mSpaceWidth;
|
||||||
|
nscoord mAveCharWidth;
|
||||||
|
|
||||||
PRUint16 mPixelSize;
|
PRUint16 mPixelSize;
|
||||||
PRUint8 mStretchIndex;
|
PRUint8 mStretchIndex;
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
#include "prmem.h"
|
#include "prmem.h"
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
|
#include "prenv.h"
|
||||||
#include "nsGCCache.h"
|
#include "nsGCCache.h"
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
#include "gfxIImageFrame.h"
|
#include "gfxIImageFrame.h"
|
||||||
@ -250,6 +251,50 @@ nsRenderingContextXlib::GetHints(PRUint32& aResult)
|
|||||||
// XChar2b rendering. In addition, we can avoid the PRUnichar to
|
// XChar2b rendering. In addition, we can avoid the PRUnichar to
|
||||||
// XChar2b conversion. So we set this bit...
|
// XChar2b conversion. So we set this bit...
|
||||||
result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
|
result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
|
||||||
|
|
||||||
|
/* We can't enable fast text measuring (yet) on platforms
|
||||||
|
* which force natural alignment of datatypes (see
|
||||||
|
* http://bugzilla.mozilla.org/show_bug.cgi?id=36146#c46) ... ;-(
|
||||||
|
*/
|
||||||
|
#ifndef CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT
|
||||||
|
#if defined(__i386)
|
||||||
|
#define CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT 1
|
||||||
|
#endif /* __i386 */
|
||||||
|
#endif /* !CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT */
|
||||||
|
|
||||||
|
static PRBool enable_fast_measure;
|
||||||
|
static PRBool getenv_done = PR_FALSE;
|
||||||
|
|
||||||
|
/* Check for the env vars "MOZILLA_GFX_ENABLE_FAST_MEASURE" and
|
||||||
|
* "MOZILLA_GFX_DISABLE_FAST_MEASURE" to enable/disable fast text
|
||||||
|
* measuring (for debugging the feature and doing regression tests).
|
||||||
|
* This code will be removed one all issues around this new feature have
|
||||||
|
* been fixed. */
|
||||||
|
if (!getenv_done)
|
||||||
|
{
|
||||||
|
#ifdef CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT
|
||||||
|
enable_fast_measure = PR_TRUE;
|
||||||
|
#else
|
||||||
|
enable_fast_measure = PR_FALSE;
|
||||||
|
#endif /* CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT */
|
||||||
|
|
||||||
|
if (PR_GetEnv("MOZILLA_GFX_ENABLE_FAST_MEASURE"))
|
||||||
|
{
|
||||||
|
enable_fast_measure = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PR_GetEnv("MOZILLA_GFX_DISABLE_FAST_MEASURE"))
|
||||||
|
{
|
||||||
|
enable_fast_measure = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
getenv_done = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable_fast_measure) {
|
||||||
|
// We have GetTextDimensions()
|
||||||
|
result |= NS_RENDERING_HINT_FAST_MEASURE;
|
||||||
|
}
|
||||||
|
|
||||||
// XXX see if we are rendering to the local display or to a remote
|
// XXX see if we are rendering to the local display or to a remote
|
||||||
// dispaly and set the NS_RENDERING_HINT_REMOTE_RENDERING accordingly
|
// dispaly and set the NS_RENDERING_HINT_REMOTE_RENDERING accordingly
|
||||||
@ -1393,6 +1438,548 @@ FoundFont:
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsRenderingContextXlib::GetTextDimensions(const char* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID)
|
||||||
|
{
|
||||||
|
NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
|
||||||
|
|
||||||
|
if (nsnull != mFontMetrics) {
|
||||||
|
// If we need to back up this state represents the last place we could
|
||||||
|
// break. We can use this to avoid remeasuring text
|
||||||
|
PRInt32 prevBreakState_BreakIndex = -1; // not known (hasn't been computed)
|
||||||
|
nscoord prevBreakState_Width = 0; // accumulated width to this point
|
||||||
|
|
||||||
|
// Initialize OUT parameters
|
||||||
|
mFontMetrics->GetMaxAscent(aLastWordDimensions.ascent);
|
||||||
|
mFontMetrics->GetMaxDescent(aLastWordDimensions.descent);
|
||||||
|
aLastWordDimensions.width = -1;
|
||||||
|
aNumCharsFit = 0;
|
||||||
|
|
||||||
|
// Iterate each character in the string and determine which font to use
|
||||||
|
nscoord width = 0;
|
||||||
|
PRInt32 start = 0;
|
||||||
|
nscoord aveCharWidth;
|
||||||
|
mFontMetrics->GetAveCharWidth(aveCharWidth);
|
||||||
|
|
||||||
|
while (start < aLength) {
|
||||||
|
// Estimate how many characters will fit. Do that by diving the available
|
||||||
|
// space by the average character width. Make sure the estimated number
|
||||||
|
// of characters is at least 1
|
||||||
|
PRInt32 estimatedNumChars = 0;
|
||||||
|
if (aveCharWidth > 0) {
|
||||||
|
estimatedNumChars = (aAvailWidth - width) / aveCharWidth;
|
||||||
|
}
|
||||||
|
if (estimatedNumChars < 1) {
|
||||||
|
estimatedNumChars = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the nearest break offset
|
||||||
|
PRInt32 estimatedBreakOffset = start + estimatedNumChars;
|
||||||
|
PRInt32 breakIndex;
|
||||||
|
nscoord numChars;
|
||||||
|
|
||||||
|
// Find the nearest place to break that is less than or equal to
|
||||||
|
// the estimated break offset
|
||||||
|
if (aLength <= estimatedBreakOffset) {
|
||||||
|
// All the characters should fit
|
||||||
|
numChars = aLength - start;
|
||||||
|
breakIndex = aNumBreaks - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
breakIndex = prevBreakState_BreakIndex;
|
||||||
|
while (((breakIndex + 1) < aNumBreaks) &&
|
||||||
|
(aBreaks[breakIndex + 1] <= estimatedBreakOffset)) {
|
||||||
|
++breakIndex;
|
||||||
|
}
|
||||||
|
if (breakIndex == prevBreakState_BreakIndex) {
|
||||||
|
++breakIndex; // make sure we advanced past the previous break index
|
||||||
|
}
|
||||||
|
numChars = aBreaks[breakIndex] - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure the text
|
||||||
|
nscoord twWidth = 0;
|
||||||
|
if ((1 == numChars) && (aString[start] == ' ')) {
|
||||||
|
mFontMetrics->GetSpaceWidth(twWidth);
|
||||||
|
}
|
||||||
|
else if (numChars > 0)
|
||||||
|
GetWidth( &aString[start], numChars, twWidth);
|
||||||
|
|
||||||
|
// See if the text fits
|
||||||
|
PRBool textFits = (twWidth + width) <= aAvailWidth;
|
||||||
|
|
||||||
|
// If the text fits then update the width and the number of
|
||||||
|
// characters that fit
|
||||||
|
if (textFits) {
|
||||||
|
aNumCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
start += numChars;
|
||||||
|
|
||||||
|
// This is a good spot to back up to if we need to so remember
|
||||||
|
// this state
|
||||||
|
prevBreakState_BreakIndex = breakIndex;
|
||||||
|
prevBreakState_Width = width;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// See if we can just back up to the previous saved state and not
|
||||||
|
// have to measure any text
|
||||||
|
if (prevBreakState_BreakIndex > 0) {
|
||||||
|
// If the previous break index is just before the current break index
|
||||||
|
// then we can use it
|
||||||
|
if (prevBreakState_BreakIndex == (breakIndex - 1)) {
|
||||||
|
aNumCharsFit = aBreaks[prevBreakState_BreakIndex];
|
||||||
|
width = prevBreakState_Width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't just revert to the previous break state
|
||||||
|
if (0 == breakIndex) {
|
||||||
|
// There's no place to back up to, so even though the text doesn't fit
|
||||||
|
// return it anyway
|
||||||
|
aNumCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeatedly back up until we get to where the text fits or we're all
|
||||||
|
// the way back to the first word
|
||||||
|
width += twWidth;
|
||||||
|
while ((breakIndex >= 1) && (width > aAvailWidth)) {
|
||||||
|
twWidth = 0;
|
||||||
|
start = aBreaks[breakIndex - 1];
|
||||||
|
numChars = aBreaks[breakIndex] - start;
|
||||||
|
|
||||||
|
if ((1 == numChars) && (aString[start] == ' ')) {
|
||||||
|
mFontMetrics->GetSpaceWidth(twWidth);
|
||||||
|
}
|
||||||
|
else if (numChars > 0)
|
||||||
|
GetWidth( &aString[start], numChars, twWidth);
|
||||||
|
|
||||||
|
width -= twWidth;
|
||||||
|
aNumCharsFit = start;
|
||||||
|
breakIndex--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aDimensions.width = width;
|
||||||
|
mFontMetrics->GetMaxAscent(aDimensions.ascent);
|
||||||
|
mFontMetrics->GetMaxDescent(aDimensions.descent);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BreakGetTextDimensionsData {
|
||||||
|
float mP2T; // IN
|
||||||
|
PRInt32 mAvailWidth; // IN
|
||||||
|
PRInt32* mBreaks; // IN
|
||||||
|
PRInt32 mNumBreaks; // IN
|
||||||
|
nscoord mSpaceWidth; // IN
|
||||||
|
nscoord mAveCharWidth; // IN
|
||||||
|
PRInt32 mEstimatedNumChars; // IN (running -- to handle the edge case of one word)
|
||||||
|
|
||||||
|
PRInt32 mNumCharsFit; // IN/OUT -- accumulated number of chars that fit so far
|
||||||
|
nscoord mWidth; // IN/OUT -- accumulated width so far
|
||||||
|
|
||||||
|
// If we need to back up, this state represents the last place
|
||||||
|
// we could break. We can use this to avoid remeasuring text
|
||||||
|
PRInt32 mPrevBreakState_BreakIndex; // IN/OUT, initialized as -1, i.e., not yet computed
|
||||||
|
nscoord mPrevBreakState_Width; // IN/OUT, initialized as 0
|
||||||
|
|
||||||
|
// Remember the fonts that we use so that we can deal with
|
||||||
|
// line-breaking in-between fonts later. mOffsets[0] is also used
|
||||||
|
// to initialize the current offset from where to start measuring
|
||||||
|
nsVoidArray* mFonts; // OUT
|
||||||
|
nsVoidArray* mOffsets; // IN/OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
static PRBool PR_CALLBACK
|
||||||
|
do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
|
||||||
|
const PRUnichar* aSubstring,
|
||||||
|
PRUint32 aSubstringLength,
|
||||||
|
void* aData)
|
||||||
|
{
|
||||||
|
nsFontXlib *fontXlib = aFontSwitch->mFontXlib;
|
||||||
|
|
||||||
|
// Make sure the font is selected
|
||||||
|
BreakGetTextDimensionsData* data = (BreakGetTextDimensionsData*)aData;
|
||||||
|
|
||||||
|
// Our current state relative to the _full_ string...
|
||||||
|
// This allows emulation of the previous code...
|
||||||
|
const PRUnichar* pstr = (const PRUnichar*)data->mOffsets->ElementAt(0);
|
||||||
|
PRInt32 numCharsFit = data->mNumCharsFit;
|
||||||
|
nscoord width = data->mWidth;
|
||||||
|
PRInt32 start = (PRInt32)(aSubstring - pstr);
|
||||||
|
PRInt32 i = start + aSubstringLength;
|
||||||
|
PRBool allDone = PR_FALSE;
|
||||||
|
|
||||||
|
while (start < i) {
|
||||||
|
// Estimate how many characters will fit. Do that by dividing the
|
||||||
|
// available space by the average character width
|
||||||
|
PRInt32 estimatedNumChars = data->mEstimatedNumChars;
|
||||||
|
if (!estimatedNumChars && data->mAveCharWidth > 0) {
|
||||||
|
estimatedNumChars = (data->mAvailWidth - width) / data->mAveCharWidth;
|
||||||
|
}
|
||||||
|
// Make sure the estimated number of characters is at least 1
|
||||||
|
if (estimatedNumChars < 1) {
|
||||||
|
estimatedNumChars = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the nearest break offset
|
||||||
|
PRInt32 estimatedBreakOffset = start + estimatedNumChars;
|
||||||
|
PRInt32 breakIndex = -1; // not yet computed
|
||||||
|
PRBool inMiddleOfSegment = PR_FALSE;
|
||||||
|
nscoord numChars;
|
||||||
|
|
||||||
|
// Avoid scanning the break array in the case where we think all
|
||||||
|
// the text should fit
|
||||||
|
if (i <= estimatedBreakOffset) {
|
||||||
|
// Everything should fit
|
||||||
|
numChars = i - start;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Find the nearest place to break that is less than or equal to
|
||||||
|
// the estimated break offset
|
||||||
|
breakIndex = data->mPrevBreakState_BreakIndex;
|
||||||
|
while (data->mBreaks[breakIndex + 1] <= estimatedBreakOffset) {
|
||||||
|
++breakIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakIndex == -1)
|
||||||
|
breakIndex = 0;
|
||||||
|
|
||||||
|
// We found a place to break that is before the estimated break
|
||||||
|
// offset. Where we break depends on whether the text crosses a
|
||||||
|
// segment boundary
|
||||||
|
if (start < data->mBreaks[breakIndex]) {
|
||||||
|
// The text crosses at least one segment boundary so measure to the
|
||||||
|
// break point just before the estimated break offset
|
||||||
|
numChars = PR_MIN(data->mBreaks[breakIndex] - start, (PRInt32)aSubstringLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// See whether there is another segment boundary between this one
|
||||||
|
// and the end of the text
|
||||||
|
if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < i)) {
|
||||||
|
++breakIndex;
|
||||||
|
numChars = data->mBreaks[breakIndex] - start;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NS_ASSERTION(i != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
|
||||||
|
|
||||||
|
// The text is all within the same segment
|
||||||
|
numChars = i - start;
|
||||||
|
|
||||||
|
// Remember we're in the middle of a segment and not between
|
||||||
|
// two segments
|
||||||
|
inMiddleOfSegment = PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure the text
|
||||||
|
nscoord twWidth, pxWidth;
|
||||||
|
if ((1 == numChars) && (pstr[start] == ' ')) {
|
||||||
|
twWidth = data->mSpaceWidth;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pxWidth = fontXlib->GetWidth(&pstr[start], numChars);
|
||||||
|
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if the text fits
|
||||||
|
PRBool textFits = (twWidth + width) <= data->mAvailWidth;
|
||||||
|
|
||||||
|
// If the text fits then update the width and the number of
|
||||||
|
// characters that fit
|
||||||
|
if (textFits) {
|
||||||
|
numCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
|
||||||
|
// If we computed the break index and we're not in the middle
|
||||||
|
// of a segment then this is a spot that we can back up to if
|
||||||
|
// we need to, so remember this state
|
||||||
|
if ((breakIndex != -1) && !inMiddleOfSegment) {
|
||||||
|
data->mPrevBreakState_BreakIndex = breakIndex;
|
||||||
|
data->mPrevBreakState_Width = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The text didn't fit. If we're out of room then we're all done
|
||||||
|
allDone = PR_TRUE;
|
||||||
|
|
||||||
|
// See if we can just back up to the previous saved state and not
|
||||||
|
// have to measure any text
|
||||||
|
if (data->mPrevBreakState_BreakIndex != -1) {
|
||||||
|
PRBool canBackup;
|
||||||
|
|
||||||
|
// If we're in the middle of a word then the break index
|
||||||
|
// must be the same if we can use it. If we're at a segment
|
||||||
|
// boundary, then if the saved state is for the previous
|
||||||
|
// break index then we can use it
|
||||||
|
if (inMiddleOfSegment) {
|
||||||
|
canBackup = data->mPrevBreakState_BreakIndex == breakIndex;
|
||||||
|
} else {
|
||||||
|
canBackup = data->mPrevBreakState_BreakIndex == (breakIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canBackup) {
|
||||||
|
numCharsFit = data->mBreaks[data->mPrevBreakState_BreakIndex];
|
||||||
|
width = data->mPrevBreakState_Width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't just revert to the previous break state. Find the break
|
||||||
|
// index just before the end of the text
|
||||||
|
i = start + numChars;
|
||||||
|
if (breakIndex == -1) {
|
||||||
|
breakIndex = 0;
|
||||||
|
if (data->mBreaks[breakIndex] < i) {
|
||||||
|
while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < i)) {
|
||||||
|
++breakIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((0 == breakIndex) && (i <= data->mBreaks[0])) {
|
||||||
|
// There's no place to back up to, so even though the text doesn't fit
|
||||||
|
// return it anyway
|
||||||
|
numCharsFit += numChars;
|
||||||
|
width += twWidth;
|
||||||
|
|
||||||
|
// Edge case of one word: it could be that we just measured a fragment of the
|
||||||
|
// first word and its remainder involves other fonts, so we want to keep going
|
||||||
|
// until we at least measure the entire first word
|
||||||
|
if (numCharsFit < data->mBreaks[0]) {
|
||||||
|
allDone = PR_FALSE;
|
||||||
|
// From now on we don't care anymore what is the _real_ estimated
|
||||||
|
// number of characters that fits. Rather, we have no where to break
|
||||||
|
// and have to measure one word fully, but the real estimate is less
|
||||||
|
// than that one word. However, since the other bits of code rely on
|
||||||
|
// what is in "data->mEstimatedNumChars", we want to override
|
||||||
|
// "data->mEstimatedNumChars" and pass in what _has_ to be measured
|
||||||
|
// so that it is transparent to the other bits that depend on it.
|
||||||
|
data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
|
||||||
|
start += numChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeatedly back up until we get to where the text fits or we're
|
||||||
|
// all the way back to the first word
|
||||||
|
width += twWidth;
|
||||||
|
while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
|
||||||
|
twWidth = 0;
|
||||||
|
start = data->mBreaks[breakIndex];
|
||||||
|
numChars = i - start;
|
||||||
|
if ((1 == numChars) && (pstr[start] == ' ')) {
|
||||||
|
twWidth = data->mSpaceWidth;
|
||||||
|
}
|
||||||
|
else if (numChars > 0) {
|
||||||
|
pxWidth = fontXlib->GetWidth(&pstr[start], numChars);
|
||||||
|
twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
|
||||||
|
}
|
||||||
|
|
||||||
|
width -= twWidth;
|
||||||
|
numCharsFit = start;
|
||||||
|
--breakIndex;
|
||||||
|
i = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start += numChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_rbs
|
||||||
|
NS_ASSERTION(allDone || start == i, "internal error");
|
||||||
|
NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
|
||||||
|
#endif /* DEBUG_rbs */
|
||||||
|
|
||||||
|
if (data->mNumCharsFit != numCharsFit) {
|
||||||
|
// some text was actually retained
|
||||||
|
data->mWidth = width;
|
||||||
|
data->mNumCharsFit = numCharsFit;
|
||||||
|
data->mFonts->AppendElement(fontXlib);
|
||||||
|
data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allDone) {
|
||||||
|
// stop now
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_TRUE; // don't stop if we still need to measure more characters
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsRenderingContextXlib::GetTextDimensions(const PRUnichar* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID)
|
||||||
|
{
|
||||||
|
if (!mFontMetrics)
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
nsFontMetricsXlib *metrics = NS_REINTERPRET_CAST(nsFontMetricsXlib *, mFontMetrics.get());
|
||||||
|
|
||||||
|
nscoord spaceWidth, aveCharWidth;
|
||||||
|
metrics->GetSpaceWidth(spaceWidth);
|
||||||
|
metrics->GetAveCharWidth(aveCharWidth);
|
||||||
|
|
||||||
|
// Note: aBreaks[] is supplied to us so that the first word is located
|
||||||
|
// at aString[0 .. aBreaks[0]-1] and more generally, the k-th word is
|
||||||
|
// located at aString[aBreaks[k-1] .. aBreaks[k]-1]. Whitespace can
|
||||||
|
// be included and each of them counts as a word in its own right.
|
||||||
|
|
||||||
|
// Upon completion of glyph resolution, characters that can be
|
||||||
|
// represented with fonts[i] are at offsets[i] .. offsets[i+1]-1
|
||||||
|
|
||||||
|
nsAutoVoidArray fonts, offsets;
|
||||||
|
offsets.AppendElement((void*)aString);
|
||||||
|
|
||||||
|
BreakGetTextDimensionsData data = { mP2T, aAvailWidth, aBreaks, aNumBreaks,
|
||||||
|
spaceWidth, aveCharWidth, 0, 0, 0, -1, 0, &fonts, &offsets
|
||||||
|
};
|
||||||
|
|
||||||
|
metrics->ResolveForwards(aString, aLength, do_BreakGetTextDimensions, &data);
|
||||||
|
|
||||||
|
if (aFontID) *aFontID = 0;
|
||||||
|
|
||||||
|
aNumCharsFit = data.mNumCharsFit;
|
||||||
|
aDimensions.width = data.mWidth;
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// Post-processing for the ascent and descent:
|
||||||
|
//
|
||||||
|
// The width of the last word is included in the final width, but its
|
||||||
|
// ascent and descent are kept aside for the moment. The problem is that
|
||||||
|
// line-breaking may occur _before_ the last word, and we don't want its
|
||||||
|
// ascent and descent to interfere. We can re-measure the last word and
|
||||||
|
// substract its width later. However, we need a special care for the ascent
|
||||||
|
// and descent at the break-point. The idea is to keep the ascent and descent
|
||||||
|
// of the last word separate, and let layout consider them later when it has
|
||||||
|
// determined that line-breaking doesn't occur before the last word.
|
||||||
|
//
|
||||||
|
// Therefore, there are two things to do:
|
||||||
|
// 1. Determine the ascent and descent up to where line-breaking may occur.
|
||||||
|
// 2. Determine the ascent and descent of the remainder.
|
||||||
|
// For efficiency however, it is okay to bail out early if there is only
|
||||||
|
// one font (in this case, the height of the last word has no special
|
||||||
|
// effect on the total height).
|
||||||
|
|
||||||
|
// aLastWordDimensions.width should be set to -1 to reply that we don't
|
||||||
|
// know the width of the last word since we measure multiple words
|
||||||
|
aLastWordDimensions.Clear();
|
||||||
|
aLastWordDimensions.width = -1;
|
||||||
|
|
||||||
|
PRInt32 count = fonts.Count();
|
||||||
|
if (!count)
|
||||||
|
return NS_OK;
|
||||||
|
nsFontXlib *fontXlib = (nsFontXlib *)fonts[0];
|
||||||
|
NS_ASSERTION(fontXlib, "internal error in do_BreakGetTextDimensions");
|
||||||
|
aDimensions.ascent = fontXlib->mMaxAscent;
|
||||||
|
aDimensions.descent = fontXlib->mMaxDescent;
|
||||||
|
|
||||||
|
// fast path - normal case, quick return if there is only one font
|
||||||
|
if (count == 1)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
// get the last break index.
|
||||||
|
// If there is only one word, we end up with lastBreakIndex = 0. We don't
|
||||||
|
// need to worry about aLastWordDimensions in this case too. But if we didn't
|
||||||
|
// return earlier, it would mean that the unique word needs several fonts
|
||||||
|
// and we will still have to loop over the fonts to return the final height
|
||||||
|
PRInt32 lastBreakIndex = 0;
|
||||||
|
while (aBreaks[lastBreakIndex] < aNumCharsFit)
|
||||||
|
++lastBreakIndex;
|
||||||
|
|
||||||
|
const PRUnichar* lastWord = (lastBreakIndex > 0)
|
||||||
|
? aString + aBreaks[lastBreakIndex-1]
|
||||||
|
: aString + aNumCharsFit; // let it point outside to play nice with the loop
|
||||||
|
|
||||||
|
// now get the desired ascent and descent information... this is however
|
||||||
|
// a very fast loop of the order of the number of additional fonts
|
||||||
|
|
||||||
|
PRInt32 currFont = 0;
|
||||||
|
const PRUnichar* pstr = aString;
|
||||||
|
const PRUnichar* last = aString + aNumCharsFit;
|
||||||
|
|
||||||
|
while (pstr < last) {
|
||||||
|
fontXlib = (nsFontXlib*)fonts[currFont];
|
||||||
|
PRUnichar* nextOffset = (PRUnichar*)offsets[++currFont];
|
||||||
|
|
||||||
|
// For consistent word-wrapping, we are going to handle the whitespace
|
||||||
|
// character with special care because a whitespace character can come
|
||||||
|
// from a font different from that of the previous word. If 'x', 'y', 'z',
|
||||||
|
// are Unicode points that require different fonts, we want 'xyz <br>'
|
||||||
|
// and 'xyz<br>' to have the same height because it gives a more stable
|
||||||
|
// rendering, especially when the window is resized at the edge of the word.
|
||||||
|
// If we don't do this, a 'tall' trailing whitespace, i.e., if the whitespace
|
||||||
|
// happens to come from a font with a bigger ascent and/or descent than all
|
||||||
|
// current fonts on the line, this can cause the next lines to be shifted
|
||||||
|
// down when the window is slowly resized to fit that whitespace.
|
||||||
|
if (*pstr == ' ') {
|
||||||
|
// skip pass the whitespace to ignore the height that it may contribute
|
||||||
|
++pstr;
|
||||||
|
// get out if we reached the end
|
||||||
|
if (pstr == last) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// switch to the next font if we just passed the current font
|
||||||
|
if (pstr == nextOffset) {
|
||||||
|
fontXlib = (nsFontXlib*)fonts[currFont];
|
||||||
|
nextOffset = (PRUnichar*)offsets[++currFont];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if the last word intersects with the current font
|
||||||
|
// (we are testing for 'nextOffset-1 >= lastWord' since the
|
||||||
|
// current font ends at nextOffset-1)
|
||||||
|
if (nextOffset > lastWord) {
|
||||||
|
if (aLastWordDimensions.ascent < fontXlib->mMaxAscent) {
|
||||||
|
aLastWordDimensions.ascent = fontXlib->mMaxAscent;
|
||||||
|
}
|
||||||
|
if (aLastWordDimensions.descent < fontXlib->mMaxDescent) {
|
||||||
|
aLastWordDimensions.descent = fontXlib->mMaxDescent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we have not reached the last word yet
|
||||||
|
if (pstr < lastWord) {
|
||||||
|
if (aDimensions.ascent < fontXlib->mMaxAscent) {
|
||||||
|
aDimensions.ascent = fontXlib->mMaxAscent;
|
||||||
|
}
|
||||||
|
if (aDimensions.descent < fontXlib->mMaxDescent) {
|
||||||
|
aDimensions.descent = fontXlib->mMaxDescent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// advance to where the next font starts
|
||||||
|
pstr = nextOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsRenderingContextXlib::GetTextDimensions(const char* aString, PRUint32 aLength,
|
nsRenderingContextXlib::GetTextDimensions(const char* aString, PRUint32 aLength,
|
||||||
nsTextDimensions& aDimensions)
|
nsTextDimensions& aDimensions)
|
||||||
|
@ -173,6 +173,24 @@ public:
|
|||||||
nsTextDimensions& aDimensions);
|
nsTextDimensions& aDimensions);
|
||||||
NS_IMETHOD GetTextDimensions(const PRUnichar *aString, PRUint32 aLength,
|
NS_IMETHOD GetTextDimensions(const PRUnichar *aString, PRUint32 aLength,
|
||||||
nsTextDimensions& aDimensions, PRInt32 *aFontID);
|
nsTextDimensions& aDimensions, PRInt32 *aFontID);
|
||||||
|
NS_IMETHOD GetTextDimensions(const char* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID = nsnull);
|
||||||
|
NS_IMETHOD GetTextDimensions(const PRUnichar* aString,
|
||||||
|
PRInt32 aLength,
|
||||||
|
PRInt32 aAvailWidth,
|
||||||
|
PRInt32* aBreaks,
|
||||||
|
PRInt32 aNumBreaks,
|
||||||
|
nsTextDimensions& aDimensions,
|
||||||
|
PRInt32& aNumCharsFit,
|
||||||
|
nsTextDimensions& aLastWordDimensions,
|
||||||
|
PRInt32* aFontID = nsnull);
|
||||||
|
|
||||||
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY);
|
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY);
|
||||||
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY,
|
NS_IMETHOD DrawImage(nsIImage *aImage, nscoord aX, nscoord aY,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
||||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||||
* Prabhat Hegde <prabhat.hegde@sun.com>
|
* Prabhat Hegde <prabhat.hegde@sun.com>
|
||||||
|
* Tomi Leppikangas <tomi.leppikangas@oulu.fi>
|
||||||
|
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -565,9 +567,9 @@ public:
|
|||||||
SetFontFromStyle(&aRenderingContext, sc); // some users of the struct expect this state
|
SetFontFromStyle(&aRenderingContext, sc); // some users of the struct expect this state
|
||||||
aRenderingContext.GetFontMetrics(mNormalFont);
|
aRenderingContext.GetFontMetrics(mNormalFont);
|
||||||
mNormalFont->GetSpaceWidth(mSpaceWidth);
|
mNormalFont->GetSpaceWidth(mSpaceWidth);
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
#if defined(_WIN32) || defined(XP_OS2)|| defined(MOZ_X11)
|
||||||
mNormalFont->GetAveCharWidth(mAveCharWidth);
|
mNormalFont->GetAveCharWidth(mAveCharWidth);
|
||||||
#endif
|
#endif /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
if (0 == mAveCharWidth) {
|
if (0 == mAveCharWidth) {
|
||||||
// provide a default if it could not be resolved
|
// provide a default if it could not be resolved
|
||||||
mAveCharWidth = 10;
|
mAveCharWidth = 10;
|
||||||
@ -4534,6 +4536,8 @@ TransformTextToUnicode(char* aText, PRInt32 aNumChars)
|
|||||||
PRUnichar* cp2 = (PRUnichar*)aText + (aNumChars - 1);
|
PRUnichar* cp2 = (PRUnichar*)aText + (aNumChars - 1);
|
||||||
|
|
||||||
while (aNumChars-- > 0) {
|
while (aNumChars-- > 0) {
|
||||||
|
// XXX: If you crash here then you may see the issue described
|
||||||
|
// in http://bugzilla.mozilla.org/show_bug.cgi?id=36146#c44
|
||||||
*cp2-- = PRUnichar(*cp1--);
|
*cp2-- = PRUnichar(*cp1--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4562,15 +4566,19 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
|||||||
PRBool endsInNewline = PR_FALSE;
|
PRBool endsInNewline = PR_FALSE;
|
||||||
PRBool justDidFirstLetter = PR_FALSE;
|
PRBool justDidFirstLetter = PR_FALSE;
|
||||||
nsTextDimensions dimensions, lastWordDimensions;
|
nsTextDimensions dimensions, lastWordDimensions;
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
PRBool measureTextRuns = PR_FALSE;
|
||||||
PRBool measureTextRuns = !aTextData.mComputeMaxWordWidth && !aTs.mPreformatted &&
|
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11)
|
||||||
!aTs.mSmallCaps && !aTs.mWordSpacing && !aTs.mLetterSpacing &&
|
// see if we have implementation for GetTextDimensions()
|
||||||
aTextData.mWrapping;
|
PRUint32 hints = 0;
|
||||||
|
aReflowState.rendContext->GetHints(hints);
|
||||||
|
if (hints & NS_RENDERING_HINT_FAST_MEASURE) {
|
||||||
|
measureTextRuns = !aTextData.mComputeMaxWordWidth && !aTs.mPreformatted &&
|
||||||
|
!aTs.mSmallCaps && !aTs.mWordSpacing && !aTs.mLetterSpacing &&
|
||||||
|
aTextData.mWrapping;
|
||||||
|
}
|
||||||
// Don't measure text runs with letter spacing active, it doesn't work
|
// Don't measure text runs with letter spacing active, it doesn't work
|
||||||
// it also doesn't work if we are not word-wrapping (bug 42832)
|
// it also doesn't work if we are not word-wrapping (bug 42832)
|
||||||
#else
|
#endif /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
PRBool measureTextRuns = PR_FALSE;
|
|
||||||
#endif
|
|
||||||
TextRun textRun;
|
TextRun textRun;
|
||||||
PRInt32 estimatedNumChars;
|
PRInt32 estimatedNumChars;
|
||||||
|
|
||||||
@ -4853,7 +4861,9 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
MeasureTextRun:
|
MeasureTextRun:
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11)
|
||||||
|
// see if we have implementation for GetTextDimensions()
|
||||||
|
if (hints & NS_RENDERING_HINT_FAST_MEASURE) {
|
||||||
PRInt32 numCharsFit;
|
PRInt32 numCharsFit;
|
||||||
// These calls can return numCharsFit not positioned at a break in the textRun. Beware.
|
// These calls can return numCharsFit not positioned at a break in the textRun. Beware.
|
||||||
if (aTx.TransformedTextIsAscii()) {
|
if (aTx.TransformedTextIsAscii()) {
|
||||||
@ -4961,9 +4971,10 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
|||||||
// Estimate the remaining number of characters we think will fit
|
// Estimate the remaining number of characters we think will fit
|
||||||
estimatedNumChars = (maxWidth - aTextData.mX) / aTs.mAveCharWidth;
|
estimatedNumChars = (maxWidth - aTextData.mX) / aTs.mAveCharWidth;
|
||||||
estimatedNumChars += estimatedNumChars / 20;
|
estimatedNumChars += estimatedNumChars / 20;
|
||||||
#else
|
}
|
||||||
|
#else /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
int unused = -1;
|
int unused = -1;
|
||||||
#endif
|
#endif /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't actually measure any text, then make sure it looks
|
// If we didn't actually measure any text, then make sure it looks
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
* Roger B. Sidje <rbs@maths.uq.edu.au>
|
||||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||||
* Prabhat Hegde <prabhat.hegde@sun.com>
|
* Prabhat Hegde <prabhat.hegde@sun.com>
|
||||||
|
* Tomi Leppikangas <tomi.leppikangas@oulu.fi>
|
||||||
|
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
@ -565,9 +567,9 @@ public:
|
|||||||
SetFontFromStyle(&aRenderingContext, sc); // some users of the struct expect this state
|
SetFontFromStyle(&aRenderingContext, sc); // some users of the struct expect this state
|
||||||
aRenderingContext.GetFontMetrics(mNormalFont);
|
aRenderingContext.GetFontMetrics(mNormalFont);
|
||||||
mNormalFont->GetSpaceWidth(mSpaceWidth);
|
mNormalFont->GetSpaceWidth(mSpaceWidth);
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
#if defined(_WIN32) || defined(XP_OS2)|| defined(MOZ_X11)
|
||||||
mNormalFont->GetAveCharWidth(mAveCharWidth);
|
mNormalFont->GetAveCharWidth(mAveCharWidth);
|
||||||
#endif
|
#endif /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
if (0 == mAveCharWidth) {
|
if (0 == mAveCharWidth) {
|
||||||
// provide a default if it could not be resolved
|
// provide a default if it could not be resolved
|
||||||
mAveCharWidth = 10;
|
mAveCharWidth = 10;
|
||||||
@ -4534,6 +4536,8 @@ TransformTextToUnicode(char* aText, PRInt32 aNumChars)
|
|||||||
PRUnichar* cp2 = (PRUnichar*)aText + (aNumChars - 1);
|
PRUnichar* cp2 = (PRUnichar*)aText + (aNumChars - 1);
|
||||||
|
|
||||||
while (aNumChars-- > 0) {
|
while (aNumChars-- > 0) {
|
||||||
|
// XXX: If you crash here then you may see the issue described
|
||||||
|
// in http://bugzilla.mozilla.org/show_bug.cgi?id=36146#c44
|
||||||
*cp2-- = PRUnichar(*cp1--);
|
*cp2-- = PRUnichar(*cp1--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4562,15 +4566,19 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
|||||||
PRBool endsInNewline = PR_FALSE;
|
PRBool endsInNewline = PR_FALSE;
|
||||||
PRBool justDidFirstLetter = PR_FALSE;
|
PRBool justDidFirstLetter = PR_FALSE;
|
||||||
nsTextDimensions dimensions, lastWordDimensions;
|
nsTextDimensions dimensions, lastWordDimensions;
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
PRBool measureTextRuns = PR_FALSE;
|
||||||
PRBool measureTextRuns = !aTextData.mComputeMaxWordWidth && !aTs.mPreformatted &&
|
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11)
|
||||||
!aTs.mSmallCaps && !aTs.mWordSpacing && !aTs.mLetterSpacing &&
|
// see if we have implementation for GetTextDimensions()
|
||||||
aTextData.mWrapping;
|
PRUint32 hints = 0;
|
||||||
|
aReflowState.rendContext->GetHints(hints);
|
||||||
|
if (hints & NS_RENDERING_HINT_FAST_MEASURE) {
|
||||||
|
measureTextRuns = !aTextData.mComputeMaxWordWidth && !aTs.mPreformatted &&
|
||||||
|
!aTs.mSmallCaps && !aTs.mWordSpacing && !aTs.mLetterSpacing &&
|
||||||
|
aTextData.mWrapping;
|
||||||
|
}
|
||||||
// Don't measure text runs with letter spacing active, it doesn't work
|
// Don't measure text runs with letter spacing active, it doesn't work
|
||||||
// it also doesn't work if we are not word-wrapping (bug 42832)
|
// it also doesn't work if we are not word-wrapping (bug 42832)
|
||||||
#else
|
#endif /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
PRBool measureTextRuns = PR_FALSE;
|
|
||||||
#endif
|
|
||||||
TextRun textRun;
|
TextRun textRun;
|
||||||
PRInt32 estimatedNumChars;
|
PRInt32 estimatedNumChars;
|
||||||
|
|
||||||
@ -4853,7 +4861,9 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
MeasureTextRun:
|
MeasureTextRun:
|
||||||
#if defined(_WIN32) || defined(XP_OS2)
|
#if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11)
|
||||||
|
// see if we have implementation for GetTextDimensions()
|
||||||
|
if (hints & NS_RENDERING_HINT_FAST_MEASURE) {
|
||||||
PRInt32 numCharsFit;
|
PRInt32 numCharsFit;
|
||||||
// These calls can return numCharsFit not positioned at a break in the textRun. Beware.
|
// These calls can return numCharsFit not positioned at a break in the textRun. Beware.
|
||||||
if (aTx.TransformedTextIsAscii()) {
|
if (aTx.TransformedTextIsAscii()) {
|
||||||
@ -4961,9 +4971,10 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
|||||||
// Estimate the remaining number of characters we think will fit
|
// Estimate the remaining number of characters we think will fit
|
||||||
estimatedNumChars = (maxWidth - aTextData.mX) / aTs.mAveCharWidth;
|
estimatedNumChars = (maxWidth - aTextData.mX) / aTs.mAveCharWidth;
|
||||||
estimatedNumChars += estimatedNumChars / 20;
|
estimatedNumChars += estimatedNumChars / 20;
|
||||||
#else
|
}
|
||||||
|
#else /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
int unused = -1;
|
int unused = -1;
|
||||||
#endif
|
#endif /* defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) */
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't actually measure any text, then make sure it looks
|
// If we didn't actually measure any text, then make sure it looks
|
||||||
|
Loading…
Reference in New Issue
Block a user