Bug #260663. When pango is available use it for grapheme cluster information to figure out where valid selection points are. Change text rendering to use clip regions for rendering selected strings instead of rendering partial strings instead. r+sr=roc,a=asa

This commit is contained in:
blizzard%redhat.com 2005-05-02 20:48:32 +00:00
Родитель ee359bfc45
Коммит 7a4c1d728f
14 изменённых файлов: 839 добавлений и 118 удалений

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

@ -799,6 +799,84 @@ public:
nscoord aXImageStart, nscoord aYImageStart,
const nsRect * aTargetRect) = 0;
/**
* Get cluster details for a chunk of text.
*
* This will fill in the aClusterStarts array with information about
* what characters are the start of clusters for display. The
* information is just a bitfield that is set to 1 if the character
* is the start of a cluster. aClusterStarts must already be
* allocated to at least aLength items in length. Array index zero
* being set to one indicates that the first character is the
* beginning of a cluster.
*
* @param aText Text on which to get details.
* @param aLength Length of the text.
* @param aClusterStarts Array of ints that will be populated
* with information about which characters are the starts
* of clusters.
*
*/
NS_IMETHOD GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts) = 0;
/**
* Find the closest cursor position for a given x coordinate.
*
* This will find the closest byte index for a given x coordinate.
* This takes into account grapheme clusters and bidi text.
*
* @param aText Text on which to operate.
* @param aLength Length of the text.
* @param aPt the x/y position in the string to check.
*
* @return Index where the cursor falls. If the return is zero,
* it's before the first character, if it falls off the end of
* the string it's the length of the string + 1.
*
*/
virtual PRInt32 GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt) = 0;
/**
* Get the width for the specific range of a given string.
*
* This function is similar to other GetWidth functions, except that
* it gets the width for a part of the string instead of the entire
* string. This is useful when you're interested in finding out the
* length of a chunk in the middle of the string. Lots of languages
* require you to include surrounding information to accurately
* determine the length of a substring.
*
* @param aText Text on which to operate
* @param aLength Length of the text
* @param aStart Start index into the string
* @param aEnd End index into the string (inclusive)
* @param aWidth Returned with in app coordinates
*
*/
NS_IMETHOD GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth) = 0;
/**
* Get the width for the specific range of a given string.
*
* Same as GetRangeWidth for PRUnichar, but takes a char * as the
* text argument.
*
*/
NS_IMETHOD GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth) = 0;
/**
* Render an encapsulated postscript object onto the current rendering
* surface.
@ -857,6 +935,12 @@ public:
*/
#define NS_RENDERING_HINT_FAST_MEASURE 0x10
/**
* This bit, when set, indicates that the gfx supports describing
* cluster information in a string
*/
#define NS_RENDERING_HINT_TEXT_CLUSTERS 0x20
/**
* This bit, when set, indicates that gfx performs glyph reordering of complex
* text after applying character or word spacing, and so expects to be passed

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

@ -4726,6 +4726,43 @@ nsFontMetricsGTK::SetRightToLeftText(PRBool aIsRTL)
return NS_OK;
}
nsresult
nsFontMetricsGTK::GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
PRInt32
nsFontMetricsGTK::GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt)
{
return -1;
}
nsresult
nsFontMetricsGTK::GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFontMetricsGTK::GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
PR_BEGIN_EXTERN_C
static int
CompareSizes(const void* aArg1, const void* aArg2, void *data)

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

@ -348,6 +348,26 @@ public:
virtual nsresult SetRightToLeftText(PRBool aIsRTL);
virtual nsresult GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts);
virtual PRInt32 GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt);
virtual nsresult GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
virtual nsresult GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
static nsresult FamilyExists(nsIDeviceContext *aDevice, const nsString& aName);
static PRUint32 GetHints(void);

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

@ -144,6 +144,7 @@ nsFontMetricsPango::nsFontMetricsPango()
mRTLPangoContext = nsnull;
mPangoAttrList = nsnull;
mIsRTL = PR_FALSE;
mPangoSpaceWidth = 0;
static PRBool initialized = PR_FALSE;
if (initialized)
@ -342,6 +343,14 @@ nsFontMetricsPango::CacheFontMetrics(void)
// mMaxAdvance
mMaxAdvance = nscoord(xftFont->max_advance_width * f);
// mPangoSpaceWidth
PangoLayout *layout = pango_layout_new(mPangoContext);
pango_layout_set_text(layout, " ", 1);
int pswidth, psheight;
pango_layout_get_size(layout, &pswidth, &psheight);
mPangoSpaceWidth = pswidth;
g_object_unref(layout);
// mSpaceWidth (width of a space)
nscoord tmpWidth;
GetWidth(" ", 1, tmpWidth, NULL);
@ -475,17 +484,18 @@ nsFontMetricsPango::GetWidth(const char* aString, PRUint32 aLength,
pango_layout_set_text(layout, aString, aLength);
if (mPangoSpaceWidth)
FixupSpaceWidths(layout, aString);
int width, height;
pango_layout_get_size(layout, &width, &height);
width /= PANGO_SCALE;
g_object_unref(layout);
float f;
f = mDeviceContext->DevUnitsToAppUnits();
aWidth = NSToCoordRound(width * f);
aWidth = NSToCoordRound(width * f / PANGO_SCALE);
// printf("GetWidth (char *) %d\n", aWidth);
@ -516,13 +526,12 @@ nsFontMetricsPango::GetWidth(const PRUnichar* aString, PRUint32 aLength,
gint width, height;
pango_layout_set_text(layout, text, strlen(text));
FixupSpaceWidths(layout, text);
pango_layout_get_size(layout, &width, &height);
width /= PANGO_SCALE;
float f;
f = mDeviceContext->DevUnitsToAppUnits();
aWidth = NSToCoordRound(width * f);
aWidth = NSToCoordRound(width * f / PANGO_SCALE);
// printf("GetWidth %d\n", aWidth);
@ -563,6 +572,7 @@ nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
pango_layout_set_text(layout, text, strlen(text));
FixupSpaceWidths(layout, text);
// Get the logical extents
PangoLayoutLine *line;
@ -577,9 +587,9 @@ nsFontMetricsPango::GetTextDimensions(const PRUnichar* aString,
float P2T;
P2T = mDeviceContext->DevUnitsToAppUnits();
aDimensions.width = NSToCoordRound(rect.width / PANGO_SCALE * P2T);
aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) / PANGO_SCALE * P2T);
aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) / PANGO_SCALE * P2T);
aDimensions.width = NSToCoordRound(rect.width * P2T / PANGO_SCALE);
aDimensions.ascent = NSToCoordRound(PANGO_ASCENT(rect) * P2T / PANGO_SCALE);
aDimensions.descent = NSToCoordRound(PANGO_DESCENT(rect) * P2T / PANGO_SCALE);
// printf("GetTextDimensions %d %d %d\n", aDimensions.width,
//aDimensions.ascent, aDimensions.descent);
@ -705,6 +715,7 @@ nsFontMetricsPango::DrawString(const char *aString, PRUint32 aLength,
PangoLayout *layout = pango_layout_new(mPangoContext);
pango_layout_set_text(layout, aString, aLength);
FixupSpaceWidths(layout, aString);
int x = aX;
int y = aY;
@ -768,6 +779,7 @@ nsFontMetricsPango::DrawString(const PRUnichar* aString, PRUint32 aLength,
}
pango_layout_set_text(layout, text, strlen(text));
FixupSpaceWidths(layout, text);
aContext->GetTranMatrix()->TransformCoord(&x, &y);
@ -837,6 +849,7 @@ nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
}
pango_layout_set_text(layout, text, strlen(text));
FixupSpaceWidths(layout, text);
// Get the logical extents
PangoLayoutLine *line;
@ -853,12 +866,12 @@ nsFontMetricsPango::GetBoundingMetrics(const PRUnichar *aString,
P2T = mDeviceContext->DevUnitsToAppUnits();
aBoundingMetrics.leftBearing =
NSToCoordRound(rect.x / PANGO_SCALE * P2T);
NSToCoordRound(rect.x * P2T / PANGO_SCALE);
aBoundingMetrics.rightBearing =
NSToCoordRound(rect.width / PANGO_SCALE * P2T);
aBoundingMetrics.width = NSToCoordRound((rect.x + rect.width) / PANGO_SCALE * P2T);
aBoundingMetrics.ascent = NSToCoordRound(rect.y / PANGO_SCALE * P2T);
aBoundingMetrics.descent = NSToCoordRound(rect.height / PANGO_SCALE * P2T);
NSToCoordRound(rect.width * P2T / PANGO_SCALE);
aBoundingMetrics.width = NSToCoordRound((rect.x + rect.width) * P2T / PANGO_SCALE);
aBoundingMetrics.ascent = NSToCoordRound(rect.y * P2T / PANGO_SCALE);
aBoundingMetrics.descent = NSToCoordRound(rect.height * P2T / PANGO_SCALE);
loser:
g_free(text);
@ -897,6 +910,237 @@ nsFontMetricsPango::SetRightToLeftText(PRBool aIsRTL)
return NS_OK;
}
nsresult
nsFontMetricsPango::GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts)
{
nsresult rv = NS_OK;
PangoLogAttr *attrs = NULL;
gint n_attrs = 0;
PangoLayout *layout = pango_layout_new(mPangoContext);
// Convert the incoming UTF-16 to UTF-8
gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
if (!text) {
#ifdef DEBUG
NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
DUMP_PRUNICHAR(aText, aLength)
#endif
rv = NS_ERROR_FAILURE;
goto loser;
}
// Set up the pango layout
pango_layout_set_text(layout, text, strlen(text));
FixupSpaceWidths(layout, text);
// Convert back to UTF-16 while filling in the cluster info
// structure.
pango_layout_get_log_attrs(layout, &attrs, &n_attrs);
for (PRUint32 pos = 0; pos < aLength; pos++) {
if (IS_HIGH_SURROGATE(aText[pos])) {
aClusterStarts[pos] = 1;
pos++;
}
else {
aClusterStarts[pos] = attrs[pos].is_cursor_position;
}
}
loser:
if (attrs)
g_free(attrs);
if (text)
g_free(text);
if (layout)
g_object_unref(layout);
return rv;
}
PRInt32
nsFontMetricsPango::GetPosition(const PRUnichar *aText, PRUint32 aLength,
nsPoint aPt)
{
int trailing = 0;
int inx = 0;
gboolean found = FALSE;
const gchar *curChar;
PRInt32 retval = 0;
float f = mDeviceContext->AppUnitsToDevUnits();
PangoLayout *layout = pango_layout_new(mPangoContext);
PRUint32 localX = (PRUint32)(aPt.x * PANGO_SCALE * f);
PRUint32 localY = (PRUint32)(aPt.y * PANGO_SCALE * f);
// Convert the incoming UTF-16 to UTF-8
gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
if (!text) {
#ifdef DEBUG
NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
DUMP_PRUNICHAR(aText, aLength)
#endif
retval = -1;
goto loser;
}
// Set up the pango layout
pango_layout_set_text(layout, text, strlen(text));
FixupSpaceWidths(layout, text);
found = pango_layout_xy_to_index(layout, localX, localY,
&inx, &trailing);
// Convert the index back to the utf-16 index
curChar = text;
// Jump to the end if it's not found.
if (!found) {
if (inx = 0)
retval = 0;
else if (trailing)
retval = aLength;
goto loser;
}
for (PRUint32 curOffset=0; curOffset < aLength;
curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
// Check for a match before checking for a surrogate pair
if (curChar - text == inx) {
retval = curOffset;
break;
}
if (IS_HIGH_SURROGATE(aText[curOffset]))
curOffset++;
}
// If there was a trailing result, advance the index pointer the
// number of characters equal to the trailing result.
while (trailing) {
retval++;
// Yes, this can make aInx > length to indicate the end of the
// string.
if (retval < (PRInt32)aLength && IS_HIGH_SURROGATE(aText[retval]))
retval++;
trailing--;
}
loser:
if (text)
g_free(text);
if (layout)
g_object_unref(layout);
return retval;
}
nsresult
nsFontMetricsPango::GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
nsresult rv = NS_OK;
PRUint32 utf8Start = 0;
PRUint32 utf8End = 0;
aWidth = 0;
// Convert the incoming UTF-16 to UTF-8
gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL);
gchar *curChar = text;
if (!text) {
#ifdef DEBUG
NS_WARNING("nsFontMetricsPango::GetWidth invalid unicode to follow");
DUMP_PRUNICHAR(aText, aLength)
#endif
rv = NS_ERROR_FAILURE;
goto loser;
}
// Convert the utf16 offsets into utf8 offsets
for (PRUint32 curOffset = 0; curOffset < aLength;
curOffset++, curChar = g_utf8_find_next_char(curChar, NULL)) {
if (curOffset == aStart)
utf8Start = curChar - text;
if (curOffset == aEnd)
utf8End = curChar - text;
if (IS_HIGH_SURROGATE(aText[curOffset]))
curOffset++;
}
// Special case where the end index is the same as the length
if (aLength == aEnd)
utf8End = strlen(text);
rv = GetRangeWidth(text, strlen(text), utf8Start, utf8End, aWidth);
loser:
if (text)
g_free(text);
return rv;
}
nsresult
nsFontMetricsPango::GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
nsresult rv = NS_OK;
int *ranges = NULL;
int n_ranges = 0;
float f;
aWidth = 0;
PangoLayout *layout = pango_layout_new(mPangoContext);
if (!aText) {
rv = NS_ERROR_FAILURE;
goto loser;
}
pango_layout_set_text(layout, aText, aLength);
FixupSpaceWidths(layout, aText);
PangoLayoutLine *line;
if (pango_layout_get_line_count(layout) != 1) {
printf("Warning: more than one line!\n");
}
line = pango_layout_get_line(layout, 0);
pango_layout_line_get_x_ranges(line, aStart, aEnd, &ranges, &n_ranges);
aWidth = (ranges[((n_ranges - 1) * 2) + 1] - ranges[0]);
f = mDeviceContext-> DevUnitsToAppUnits();
aWidth = nscoord(aWidth * f / PANGO_SCALE);
loser:
if (ranges)
g_free(ranges);
if (layout)
g_object_unref(layout);
return rv;
}
/* static */
PRUint32
nsFontMetricsPango::GetHints(void)
@ -904,7 +1148,8 @@ nsFontMetricsPango::GetHints(void)
return (NS_RENDERING_HINT_BIDI_REORDERING |
NS_RENDERING_HINT_ARABIC_SHAPING |
NS_RENDERING_HINT_FAST_MEASURE |
NS_RENDERING_HINT_REORDER_SPACED_TEXT);
NS_RENDERING_HINT_REORDER_SPACED_TEXT |
NS_RENDERING_HINT_TEXT_CLUSTERS);
}
/* static */
@ -1020,6 +1265,10 @@ nsFontMetricsPango::RealizeFont(void)
mLTRPangoContext = pango_xft_get_context(GDK_DISPLAY(), 0);
mPangoContext = mLTRPangoContext;
// Make sure to set the base direction to LTR - if layout needs to
// render RTL text it will use ::SetRightToLeftText()
pango_context_set_base_dir(mPangoContext, PANGO_DIRECTION_LTR);
// Set the color map so we can draw later.
gdk_pango_context_set_colormap(mPangoContext, gdk_rgb_get_cmap());
@ -1128,13 +1377,11 @@ nsFontMetricsPango::DrawStringSlowly(const gchar *aText,
}
/* printf(" rendering at X coord %d\n", aX + offset); */
gdk_draw_glyphs(aDrawable, aGC, layoutRun->item->analysis.font,
aX + (gint)(offset / PANGO_SCALE), aY, layoutRun->glyphs);
offset += tmpOffset;
}
gdk_draw_layout_line(aDrawable, aGC, aX, aY, aLine);
delete[] utf8spacing;
}
@ -1286,6 +1533,26 @@ nsFontMetricsPango::GetTextDimensionsInternal(const gchar* aString,
return NS_OK;
}
void
nsFontMetricsPango::FixupSpaceWidths (PangoLayout *aLayout,
const char *aString)
{
PangoLayoutLine *line = pango_layout_get_line(aLayout, 0);
gint curRun = 0;
for (GSList *tmpList = line->runs; tmpList && tmpList->data;
tmpList = tmpList->next, curRun++) {
PangoLayoutRun *layoutRun = (PangoLayoutRun *)tmpList->data;
for (gint i=0; i < layoutRun->glyphs->num_glyphs; i++) {
gint thisOffset = (gint)layoutRun->glyphs->log_clusters[i] + layoutRun->item->offset;
if (aString[thisOffset] == ' ')
layoutRun->glyphs->glyphs[i].geometry.width = mPangoSpaceWidth;
}
}
}
/* static */
PRBool
IsASCIIFontName(const nsString& aName)

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

@ -195,6 +195,26 @@ public:
virtual nsresult SetRightToLeftText(PRBool aIsRTL);
virtual nsresult GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts);
virtual PRInt32 GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt);
virtual nsresult GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
virtual nsresult GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
// get hints for the font
static PRUint32 GetHints (void);
@ -240,6 +260,7 @@ private:
nscoord mMaxDescent;
nscoord mMaxAdvance;
nscoord mSpaceWidth;
nscoord mPangoSpaceWidth;
nscoord mAveCharWidth;
// Private methods
@ -266,6 +287,8 @@ private:
PRInt32& aNumCharsFit,
nsTextDimensions& aLastWordDimensions,
nsRenderingContextGTK *aContext);
void FixupSpaceWidths (PangoLayout *aLayout, const char *aString);
};
class nsFontEnumeratorPango : public nsIFontEnumerator

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

@ -735,6 +735,42 @@ nsFontMetricsXft::SetRightToLeftText(PRBool aIsRTL)
return NS_OK;
}
nsresult
nsFontMetricsXft::GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
PRInt32
nsFontMetricsXft::GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt)
{
return -1;
}
nsresult
nsFontMetricsXft::GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsFontMetricsXft::GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
PRUint32
nsFontMetricsXft::GetHints(void)
{

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

@ -204,6 +204,26 @@ public:
virtual nsresult SetRightToLeftText(PRBool aIsRTL);
virtual nsresult GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts);
virtual PRInt32 GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt);
virtual nsresult GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
virtual nsresult GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
// get hints for the font
static PRUint32 GetHints (void);

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

@ -297,98 +297,42 @@ void nsGCCache::ReuseGC(GCCacheEntry *entry, GdkGCValues *gcv, GdkGCValuesMask f
// We have old GC, reuse it and check what
// we have to change
XGCValues xvalues;
unsigned long xvalues_mask=0;
GdkGCValues xvalues;
int xvalues_mask = 0;
if (entry->clipRegion) {
// set it to none here and then set the clip region with
// gdk_gc_set_clip_region in GetGC()
xvalues.clip_mask = None;
xvalues_mask |= GCClipMask;
xvalues_mask |= GDK_GC_CLIP_MASK;
gdk_region_destroy(entry->clipRegion);
entry->clipRegion = NULL;
}
if (entry->gcv.foreground.pixel != gcv->foreground.pixel) {
xvalues.foreground = gcv->foreground.pixel;
xvalues_mask |= GCForeground;
xvalues.foreground.pixel = gcv->foreground.pixel;
xvalues_mask |= GDK_GC_FOREGROUND;
}
if (entry->gcv.function != gcv->function) {
switch (gcv->function) {
case GDK_COPY:
xvalues.function = GXcopy;
break;
case GDK_INVERT:
xvalues.function = GXinvert;
break;
case GDK_XOR:
xvalues.function = GXxor;
break;
case GDK_CLEAR:
xvalues.function = GXclear;
break;
case GDK_AND:
xvalues.function = GXand;
break;
case GDK_AND_REVERSE:
xvalues.function = GXandReverse;
break;
case GDK_AND_INVERT:
xvalues.function = GXandInverted;
break;
case GDK_NOOP:
xvalues.function = GXnoop;
break;
case GDK_OR:
xvalues.function = GXor;
break;
case GDK_EQUIV:
xvalues.function = GXequiv;
break;
case GDK_OR_REVERSE:
xvalues.function = GXorReverse;
break;
case GDK_COPY_INVERT:
xvalues.function = GXcopyInverted;
break;
case GDK_OR_INVERT:
xvalues.function = GXorInverted;
break;
case GDK_NAND:
xvalues.function = GXnand;
break;
case GDK_SET:
xvalues.function = GXset;
break;
}
xvalues_mask |= GCFunction;
xvalues.function = gcv->function;
xvalues_mask |= GDK_GC_FUNCTION;
}
if(entry->gcv.font != gcv->font && flags & GDK_GC_FONT) {
xvalues.font = ((XFontStruct *)GDK_FONT_XFONT(gcv->font))->fid;
xvalues_mask |= GCFont;
xvalues.font = gcv->font;
xvalues_mask |= GDK_GC_FONT;
}
if (entry->gcv.line_style != gcv->line_style) {
switch (gcv->line_style) {
case GDK_LINE_SOLID:
xvalues.line_style = LineSolid;
break;
case GDK_LINE_ON_OFF_DASH:
xvalues.line_style = LineOnOffDash;
break;
case GDK_LINE_DOUBLE_DASH:
xvalues.line_style = LineDoubleDash;
break;
}
xvalues_mask |= GCLineStyle;
xvalues.line_style = gcv->line_style;
xvalues_mask |= GDK_GC_LINE_STYLE;
}
if (xvalues_mask != 0) {
XChangeGC(GDK_GC_XDISPLAY(entry->gc), GDK_GC_XGC(entry->gc),
xvalues_mask, &xvalues);
gdk_gc_set_values(entry->gc, &xvalues, (GdkGCValuesMask)xvalues_mask);
}
entry->flags = flags;
entry->gcv = *gcv;
}

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

@ -125,6 +125,25 @@ public:
// Set the direction of the text rendering
virtual nsresult SetRightToLeftText(PRBool aIsRTL) = 0;
virtual nsresult GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts) = 0;
virtual PRInt32 GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt) = 0;
virtual nsresult GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth) = 0;
virtual nsresult GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth) = 0;
};
#endif /* __nsIFontMetricsGTK_h */

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

@ -1446,6 +1446,33 @@ NS_IMETHODIMP nsRenderingContextGTK::SetRightToLeftText(PRBool aIsRTL)
return mFontMetrics->SetRightToLeftText(aIsRTL);
}
NS_IMETHODIMP nsRenderingContextGTK::GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts)
{
return mFontMetrics->GetClusterInfo(aText, aLength, aClusterStarts);
}
PRInt32 nsRenderingContextGTK::GetPosition(const PRUnichar *aText, PRUint32 aLength,
nsPoint aPt)
{
return mFontMetrics->GetPosition(aText, aLength, aPt);
}
NS_IMETHODIMP nsRenderingContextGTK::GetRangeWidth(const PRUnichar *aText, PRUint32 aLength,
PRUint32 aStart, PRUint32 aEnd,
PRUint32 &aWidth)
{
return mFontMetrics->GetRangeWidth(aText, aLength, aStart, aEnd, aWidth);
}
NS_IMETHODIMP nsRenderingContextGTK::GetRangeWidth(const char *aText, PRUint32 aLength,
PRUint32 aStart, PRUint32 aEnd,
PRUint32 &aWidth)
{
return mFontMetrics->GetRangeWidth(aText, aLength, aStart, aEnd, aWidth);
}
NS_IMETHODIMP nsRenderingContextGTK::DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect)
{
UpdateGC();

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

@ -193,6 +193,20 @@ public:
NS_IMETHOD RetrieveCurrentNativeGraphicData(PRUint32 * ngd);
NS_IMETHOD SetRightToLeftText(PRBool aIsRTL);
NS_IMETHOD GetClusterInfo(const PRUnichar *aText, PRUint32 aLength,
PRUint8 *aClusterStarts);
virtual PRInt32 GetPosition(const PRUnichar *aText, PRUint32 aLength,
nsPoint aPt);
NS_IMETHOD GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
NS_IMETHOD GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
NS_IMETHOD DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect);

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

@ -107,6 +107,23 @@ public:
NS_IMETHOD DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect);
NS_IMETHOD DrawTile(imgIContainer *aImage, nscoord aXOffset, nscoord aYOffset, const nsRect * aTargetRect);
NS_IMETHOD GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts);
virtual PRInt32 GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt);
NS_IMETHOD GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
NS_IMETHOD GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth);
NS_IMETHOD RenderEPS(const nsRect& aRect, FILE *aDataFile);
protected:

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

@ -437,6 +437,42 @@ nsRenderingContextImpl::FlushRect(nscoord aX, nscoord aY, nscoord aWidth, nscoor
return NS_OK;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetClusterInfo(const PRUnichar *aText,
PRUint32 aLength,
PRUint8 *aClusterStarts)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
PRInt32
nsRenderingContextImpl::GetPosition(const PRUnichar *aText,
PRUint32 aLength,
nsPoint aPt)
{
return -1;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetRangeWidth(const PRUnichar *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsRenderingContextImpl::GetRangeWidth(const char *aText,
PRUint32 aLength,
PRUint32 aStart,
PRUint32 aEnd,
PRUint32 &aWidth)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsRenderingContextImpl::RenderEPS(const nsRect& aRect, FILE *aDataFile)
{

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

@ -202,6 +202,59 @@ nsAutoIndexBuffer::GrowTo(PRInt32 aAtLeast)
return NS_OK;
}
struct nsAutoPRUint8Buffer {
nsAutoPRUint8Buffer();
~nsAutoPRUint8Buffer();
nsresult GrowTo(PRInt32 aAtLeast);
PRUint8* mBuffer;
PRInt32 mBufferLen;
PRUint8 mAutoBuffer[TEXT_BUF_SIZE];
};
nsAutoPRUint8Buffer::nsAutoPRUint8Buffer()
: mBuffer(mAutoBuffer),
mBufferLen(TEXT_BUF_SIZE)
{
#ifdef DEBUG
memset(mAutoBuffer, 0xdd, sizeof(mAutoBuffer));
#endif
}
nsAutoPRUint8Buffer::~nsAutoPRUint8Buffer()
{
if (mBuffer && (mBuffer != mAutoBuffer)) {
delete [] mBuffer;
}
}
nsresult
nsAutoPRUint8Buffer::GrowTo(PRInt32 aAtLeast)
{
if (aAtLeast > mBufferLen)
{
PRInt32 newSize = mBufferLen * 2;
if (newSize < mBufferLen + aAtLeast) {
newSize = mBufferLen * 2 + aAtLeast;
}
PRUint8* newBuffer = new PRUint8[newSize];
if (!newBuffer) {
return NS_ERROR_OUT_OF_MEMORY;
}
#ifdef DEBUG
memset(newBuffer, 0xdd, sizeof(PRUint8) * newSize);
#endif
memcpy(newBuffer, mBuffer, sizeof(PRUint8) * mBufferLen);
if (mBuffer != mAutoBuffer) {
delete [] mBuffer;
}
mBuffer = newBuffer;
mBufferLen = newSize;
}
return NS_OK;
}
//----------------------------------------------------------------------
@ -808,6 +861,9 @@ protected:
PRBool IsChineseJapaneseLangGroup();
PRBool IsJustifiableCharacter(PRUnichar aChar, PRBool aLangIsCJ);
void FillClusterBuffer(nsPresContext *aPresContext, const PRUnichar *aText,
PRUint32 aLength, PRUint8 *aClusterStarts);
};
#ifdef ACCESSIBILITY
@ -1596,6 +1652,34 @@ nsTextFrame::IsJustifiableCharacter(PRUnichar aChar, PRBool aLangIsCJ)
return PR_FALSE;
}
void
nsTextFrame::FillClusterBuffer(nsPresContext *aPresContext, const PRUnichar *aText,
PRUint32 aLength, PRUint8 *aClusterStarts)
{
// Fill in the cluster hint information, if it's available.
nsCOMPtr<nsIRenderingContext> acx;
PRUint32 clusterHint = 0;
nsIPresShell *shell = aPresContext->GetPresShell();
if (shell) {
shell->CreateRenderingContext(this, getter_AddRefs(acx));
// Find the font metrics for this text
SetFontFromStyle(acx, mStyleContext);
if (acx)
acx->GetHints(clusterHint);
clusterHint &= NS_RENDERING_HINT_TEXT_CLUSTERS;
}
if (clusterHint) {
acx->GetClusterInfo(aText, aLength, aClusterStarts);
}
else {
memset(aClusterStarts, 1, sizeof(PRInt8) * aLength);
}
}
inline PRBool IsEndOfLine(nsFrameState aState)
{
return (aState & TEXT_IS_END_OF_LINE) ? PR_TRUE : PR_FALSE;
@ -2396,7 +2480,6 @@ nsTextFrame::PaintUnicodeText(nsPresContext* aPresContext,
PRBool isOddLevel = PR_FALSE;
#endif
if (NS_FAILED(GetTextInfoForPainting(aPresContext,
aRenderingContext,
getter_AddRefs(shell),
@ -2547,6 +2630,23 @@ nsTextFrame::PaintUnicodeText(nsPresContext* aPresContext,
sdptr = sdptr->mNext;
}
if (!hideStandardSelection) {
/*
* Text is drawn by drawing the entire string every time, but
* using clip regions to control which part of the text is shown
* (selected or unselected.) We do this because you can't
* assume that the layout of a part of text will be the same
* when it's drawn apart from the entire string. This is true
* in languages like arabic, where shaping affects entire words.
* Simply put: length("abcd") != length("ab") + length("cd") in
* some languages.
*/
// See if this rendering backend supports getting cluster
// information.
PRUint32 clusterHint = 0;
aRenderingContext.GetHints(clusterHint);
clusterHint &= NS_RENDERING_HINT_TEXT_CLUSTERS;
//while we have substrings...
//PRBool drawn = PR_FALSE;
DrawSelectionIterator iter(content, details,text,(PRUint32)textLength,aTextStyle, selectionValue, aPresContext, mStyleContext);
@ -2567,39 +2667,58 @@ nsTextFrame::PaintUnicodeText(nsPresContext* aPresContext,
//TextStyle &currentStyle = iter.CurrentStyle();
nscolor currentFGColor, currentBKColor;
PRBool isCurrentBKColorTransparent;
PRBool isSelection = iter.GetSelectionColors(&currentFGColor,
&currentBKColor,
&isCurrentBKColorTransparent);
#ifdef IBMBIDI
if (currentlength > 0
&& NS_SUCCEEDED(aRenderingContext.GetWidth(currenttext, currentlength,newWidth)))//ADJUST FOR CHAR SPACING
{
if (isRightToLeftOnBidiPlatform)
currentX -= newWidth;
#else // not IBMBIDI
if (NS_SUCCEEDED(aRenderingContext.GetWidth(currenttext, currentlength,newWidth)))//ADJUST FOR CHAR SPACING
if (currentlength > 0)
{
#endif
if (isSelection && !isPaginated)
{//DRAW RECT HERE!!!
if (!isCurrentBKColorTransparent) {
aRenderingContext.SetColor(currentBKColor);
aRenderingContext.FillRect(currentX, dy, newWidth, mRect.height);
}
if (clusterHint) {
PRUint32 tmpWidth;
rv = aRenderingContext.GetRangeWidth(text, textLength, currenttext - text,
(currenttext - text) + currentlength,
tmpWidth);
newWidth = nscoord(tmpWidth);
}
else {
rv = aRenderingContext.GetWidth(currenttext, currentlength,newWidth); //ADJUST FOR CHAR SPACING
}
if (NS_SUCCEEDED(rv)) {
if (isRightToLeftOnBidiPlatform)
currentX -= newWidth;
if (isSelection && !isPaginated)
{//DRAW RECT HERE!!!
if (!isCurrentBKColorTransparent) {
aRenderingContext.SetColor(currentBKColor);
aRenderingContext.FillRect(currentX, dy, newWidth, mRect.height);
}
currentFGColor = EnsureDifferentColors(currentFGColor, currentBKColor);
}
}
else {
newWidth = 0;
}
}
else
newWidth =0;
else {
newWidth = 0;
}
aRenderingContext.PushState();
nsRect rect(currentX, dy, newWidth, mRect.height);
aRenderingContext.SetClipRect(rect, nsClipCombine_kIntersect);
if (isPaginated && !iter.IsBeforeOrAfter()) {
aRenderingContext.SetColor(nsCSSRendering::TransformColor(aTextStyle.mColor->mColor,canDarkenColor));
aRenderingContext.DrawString(currenttext, currentlength, currentX, dy + mAscent);
aRenderingContext.DrawString(text, PRUint32(textLength), dx, dy + mAscent);
} else if (!isPaginated) {
aRenderingContext.SetColor(nsCSSRendering::TransformColor(currentFGColor,canDarkenColor));
aRenderingContext.DrawString(currenttext, currentlength, currentX, dy + mAscent);
aRenderingContext.DrawString(text, PRUint32(textLength), dx, dy + mAscent);
}
aRenderingContext.PopState();
#ifdef IBMBIDI
if (!isRightToLeftOnBidiPlatform)
#endif
@ -3507,6 +3626,16 @@ nsTextFrame::PaintAsciiText(nsPresContext* aPresContext,
//ITS OK TO CAST HERE THE RESULT WE USE WILLNOT DO BAD CONVERSION
DrawSelectionIterator iter(content, details,(PRUnichar *)text,(PRUint32)textLength,aTextStyle,
selectionValue, aPresContext, mStyleContext);
// See if this rendering backend supports getting cluster
// information.
PRUint32 clusterHint = 0;
aRenderingContext.GetHints(clusterHint);
clusterHint &= NS_RENDERING_HINT_TEXT_CLUSTERS;
nscoord foo;
aRenderingContext.GetWidth(text, textLength, foo);
if (!iter.IsDone() && iter.First())
{
nscoord currentX = dx;
@ -3518,11 +3647,23 @@ nsTextFrame::PaintAsciiText(nsPresContext* aPresContext,
//TextStyle &currentStyle = iter.CurrentStyle();
nscolor currentFGColor, currentBKColor;
PRBool isCurrentBKColorTransparent;
if (clusterHint) {
PRUint32 tmpWidth;
rv = aRenderingContext.GetRangeWidth(text, textLength, currenttext - text,
(currenttext - text) + currentlength,
tmpWidth);
newWidth = nscoord(tmpWidth);
}
else {
rv = aRenderingContext.GetWidth(currenttext, currentlength,newWidth); //ADJUST FOR CHAR SPACING
}
PRBool isSelection = iter.GetSelectionColors(&currentFGColor,
&currentBKColor,
&isCurrentBKColorTransparent);
if (NS_SUCCEEDED(aRenderingContext.GetWidth(currenttext, currentlength,newWidth)))//ADJUST FOR CHAR SPACING
{
if (NS_SUCCEEDED(rv)) {
if (isSelection && !isPaginated)
{//DRAW RECT HERE!!!
if (!isCurrentBKColorTransparent) {
@ -3531,16 +3672,25 @@ nsTextFrame::PaintAsciiText(nsPresContext* aPresContext,
}
}
}
else
else {
newWidth =0;
}
aRenderingContext.PushState();
nsRect rect(currentX, dy, newWidth, mRect.height);
aRenderingContext.SetClipRect(rect, nsClipCombine_kIntersect);
if (isPaginated && !iter.IsBeforeOrAfter()) {
aRenderingContext.DrawString(currenttext, currentlength, currentX, dy + mAscent);
aRenderingContext.SetColor(nsCSSRendering::TransformColor(aTextStyle.mColor->mColor,canDarkenColor));
aRenderingContext.DrawString(text, PRUint32(textLength), dx, dy + mAscent);
} else if (!isPaginated) {
aRenderingContext.SetColor(nsCSSRendering::TransformColor(currentFGColor,isPaginated));
aRenderingContext.DrawString(currenttext, currentlength, currentX, dy + mAscent);
aRenderingContext.SetColor(nsCSSRendering::TransformColor(currentFGColor,canDarkenColor));
aRenderingContext.DrawString(text, PRUint32(textLength), dx, dy + mAscent);
}
aRenderingContext.PopState();
currentX+=newWidth;//increment twips X start
iter.Next();
@ -3725,6 +3875,17 @@ nsTextFrame::GetPosition(nsPresContext* aPresContext,
PRInt32 textWidth = 0;
PRUnichar* text = paintBuffer.mBuffer;
// See if the font backend will do all the hard work for us.
PRUint32 clusterHint = 0;
rendContext->GetHints(clusterHint);
clusterHint &= NS_RENDERING_HINT_TEXT_CLUSTERS;
if (clusterHint) {
nsPoint pt;
pt.x = aPoint.x - origin.x;
pt.y = aPoint.y - origin.y;
indx = rendContext->GetPosition(text, textLength, pt);
}
else {
#ifdef IBMBIDI
PRBool getReversedPos = NS_GET_EMBEDDING_LEVEL(this) & 1;
nscoord posX = (getReversedPos) ?
@ -3761,6 +3922,7 @@ nsTextFrame::GetPosition(nsPresContext* aPresContext,
indx++;
}
}
}
aContentOffset = indx + mContentOffset;
//reusing wordBufMem
@ -4200,6 +4362,12 @@ nsTextFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
}
PRInt32* ip = indexBuffer.mBuffer;
nsAutoPRUint8Buffer clusterBuffer;
rv = clusterBuffer.GrowTo(mContentLength + 1);
if (NS_FAILED(rv)) {
return rv;
}
PRInt32 textLength;
nsresult result(NS_ERROR_FAILURE);
aPos->mResultContent = mContent;//do this right off
@ -4265,8 +4433,12 @@ nsTextFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
aPos->mContentOffset = 0;
PRInt32 i;
FillClusterBuffer(aPresContext, paintBuffer.mBuffer,
(PRUint32)textLength, clusterBuffer.mBuffer);
for (i = aPos->mStartOffset -1 - mContentOffset; i >=0; i--){
if ((ip[i] < ip[aPos->mStartOffset - mContentOffset]) &&
(clusterBuffer.mBuffer[ip[i] - mContentOffset]) &&
(! IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i]-mContentOffset])))
{
aPos->mContentOffset = i + mContentOffset;
@ -4317,14 +4489,19 @@ nsTextFrame::PeekOffset(nsPresContext* aPresContext, nsPeekOffsetStruct *aPos)
PRInt32 i;
aPos->mContentOffset = mContentLength;
for (i = aPos->mStartOffset +1 - mContentOffset; i <= mContentLength; i++){
FillClusterBuffer(aPresContext, paintBuffer.mBuffer,
(PRUint32)textLength, clusterBuffer.mBuffer);
for (i = aPos->mStartOffset - mContentOffset; i <= mContentLength; i++) {
if ((ip[i] > ip[aPos->mStartOffset - mContentOffset]) &&
(! IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i]-mContentOffset])))
{
((i == mContentLength) ||
(!IS_LOW_SURROGATE(paintBuffer.mBuffer[ip[i] - mContentOffset])) &&
(clusterBuffer.mBuffer[ip[i] - mContentOffset]))) {
aPos->mContentOffset = i + mContentOffset;
break;
}
}
#ifdef SUNCTL
static NS_DEFINE_CID(kLECID, NS_ULE_CID);