--- mozilla/gfx/src/gtk/nsFontMetricsXft.cpp.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsXft.cpp 2004-12-16 13:13:31.000000000 -0500 @@ -831,6 +831,33 @@ return NS_OK; } +nsresult +nsFontMetricsXft::GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +nsFontMetricsXft::GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +nsFontMetricsXft::GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + PRUint32 nsFontMetricsXft::GetHints(void) { --- mozilla/gfx/src/gtk/nsFontMetricsPango.cpp.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsPango.cpp 2004-12-16 13:13:31.000000000 -0500 @@ -907,13 +907,222 @@ return NS_OK; } +nsresult +nsFontMetricsPango::GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *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)); + + // 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; +} + +nsresult +nsFontMetricsPango::GetPosition(const PRUnichar *aText, PRUint32 aLength, + nscoord aCoord, PRUint32 &aInx) +{ + nsresult rv = NS_OK; + int trailing = 0; + int inx = 0; + gboolean found = FALSE; + const gchar *curChar; + + float f = mDeviceContext->AppUnitsToDevUnits(); + + PangoLayout *layout = pango_layout_new(mPangoContext); + PRUint32 localCoord = (PRUint32)(aCoord * 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 + rv = NS_ERROR_FAILURE; + goto loser; + } + + // Set up the pango layout + pango_layout_set_text(layout, text, strlen(text)); + + found = pango_layout_xy_to_index(layout, localCoord, 0, + &inx, &trailing); + + // Convert the index back to the utf-16 index + curChar = text; + aInx = 0; + + // Jump to the end if it's not found. + if (!found) { + if (inx = 0) + aInx = 0; + else if (trailing) + aInx = 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) { + aInx = 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) { + aInx++; + // Yes, this can make aInx > length to indicate the end of the + // string. + if (aInx < aLength && IS_HIGH_SURROGATE(aText[aInx])) + aInx++; + trailing--; + } + + loser: + if (text) + g_free(text); + if (layout) + g_object_unref(layout); + + return rv; +} + +nsresult +nsFontMetricsPango::GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth) +{ + nsresult rv = NS_OK; + int *ranges = NULL; + int n_ranges = 0; + PRUint32 utf8Start = 0; + PRUint32 utf8End = 0; + float f; + + aWidth = 0; + + // Convert the incoming UTF-16 to UTF-8 + gchar *text = g_utf16_to_utf8(aText, aLength, NULL, NULL, NULL); + gchar *curChar = text; + + PangoLayout *layout = pango_layout_new(mPangoContext); + + 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); + + pango_layout_set_text(layout, text, strlen(text)); + + 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, utf8Start, utf8End, &ranges, &n_ranges); + + // Convert the width into app units + for (int i = 0; i < n_ranges; i++) { + aWidth += (ranges[(i * 2) + 1] - ranges[(i * 2)]) / PANGO_SCALE; + } + + f = mDeviceContext-> DevUnitsToAppUnits(); + aWidth = nscoord(aWidth * f); + + loser: + if (ranges) + g_free(ranges); + if (text) + g_free(text); + if (layout) + g_object_unref(layout); + + return rv; +} + /* static */ PRUint32 nsFontMetricsPango::GetHints(void) { return (NS_RENDERING_HINT_BIDI_REORDERING | NS_RENDERING_HINT_ARABIC_SHAPING | - NS_RENDERING_HINT_FAST_MEASURE); + NS_RENDERING_HINT_FAST_MEASURE | + NS_RENDERING_HINT_TEXT_CLUSTERS); } /* static */ @@ -1137,13 +1346,11 @@ } /* 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; } --- mozilla/gfx/src/gtk/nsRenderingContextGTK.h.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsRenderingContextGTK.h 2004-12-16 13:13:31.000000000 -0500 @@ -195,6 +195,15 @@ NS_IMETHOD RetrieveCurrentNativeGraphicData(PRUint32 * ngd); NS_IMETHOD SetRightToLeftText(PRBool aIsRTL); + NS_IMETHOD GetClusterInfo(const PRUnichar *aText, PRUint32 aLength, + PRUint32 *aClusterStarts); + NS_IMETHOD GetPosition(const PRUnichar *aText, PRUint32 aLength, + nscoord aCoord, PRUint32 &aInx); + NS_IMETHOD GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth); NS_IMETHOD DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint); NS_IMETHOD DrawScaledImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsRect * aDestRect); --- mozilla/gfx/src/gtk/nsFontMetricsPango.h.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsPango.h 2004-12-16 13:13:31.000000000 -0500 @@ -195,6 +195,21 @@ virtual nsresult SetRightToLeftText(PRBool aIsRTL); + virtual nsresult GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts); + + virtual nsresult GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx); + + virtual nsresult GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth); + // get hints for the font static PRUint32 GetHints (void); --- mozilla/gfx/src/gtk/nsIFontMetricsGTK.h.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsIFontMetricsGTK.h 2004-12-16 13:13:31.000000000 -0500 @@ -124,6 +124,21 @@ // Set the direction of the text rendering virtual nsresult SetRightToLeftText(PRBool aIsRTL) = 0; + virtual nsresult GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts) = 0; + + virtual nsresult GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx) = 0; + + virtual nsresult GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth) = 0; + }; #endif /* __nsIFontMetricsGTK_h */ --- mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp 2004-12-16 13:13:31.000000000 -0500 @@ -1446,6 +1446,26 @@ return mFontMetrics->SetRightToLeftText(aIsRTL); } +NS_IMETHODIMP nsRenderingContextGTK::GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts) +{ + return mFontMetrics->GetClusterInfo(aText, aLength, aClusterStarts); +} + +NS_IMETHODIMP nsRenderingContextGTK::GetPosition(const PRUnichar *aText, PRUint32 aLength, + nscoord aCoord, PRUint32 &aInx) +{ + return mFontMetrics->GetPosition(aText, aLength, aCoord, aInx); +} + +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::DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint) { UpdateGC(); --- mozilla/gfx/src/gtk/nsFontMetricsGTK.cpp.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsGTK.cpp 2004-12-16 13:13:31.000000000 -0500 @@ -4606,6 +4606,34 @@ return NS_OK; } +nsresult +nsFontMetricsGTK::GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +nsFontMetricsGTK::GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +nsresult +nsFontMetricsGTK::GetRangeWidth(const PRUnichar *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) --- mozilla/gfx/src/gtk/nsFontMetricsXft.h.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsXft.h 2004-12-16 13:13:31.000000000 -0500 @@ -204,6 +204,21 @@ virtual nsresult SetRightToLeftText(PRBool aIsRTL); + virtual nsresult GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts); + + virtual nsresult GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx); + + virtual nsresult GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth); + // get hints for the font static PRUint32 GetHints (void); --- mozilla/gfx/src/gtk/nsFontMetricsGTK.h.foo 2004-12-16 13:12:54.000000000 -0500 +++ mozilla/gfx/src/gtk/nsFontMetricsGTK.h 2004-12-16 13:13:31.000000000 -0500 @@ -346,6 +346,21 @@ virtual nsresult SetRightToLeftText(PRBool aIsRTL); + virtual nsresult GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts); + + virtual nsresult GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx); + + virtual nsresult GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth); + static nsresult FamilyExists(nsIDeviceContext *aDevice, const nsString& aName); static PRUint32 GetHints(void); --- mozilla/gfx/src/shared/nsRenderingContextImpl.cpp.foo 2004-10-08 12:57:19.000000000 -0400 +++ mozilla/gfx/src/shared/nsRenderingContextImpl.cpp 2004-12-16 13:13:31.000000000 -0500 @@ -938,3 +938,32 @@ { return NS_OK; } + +NS_IMETHODIMP +nsRenderingContextImpl::GetClusterInfo(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 *aClusterStarts) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsRenderingContextImpl::GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsRenderingContextImpl::GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + --- mozilla/gfx/src/nsRenderingContextImpl.h.foo 2004-10-08 12:57:18.000000000 -0400 +++ mozilla/gfx/src/nsRenderingContextImpl.h 2004-12-16 13:13:31.000000000 -0500 @@ -138,6 +138,19 @@ NS_IMETHOD DrawScaledImage(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, + PRUint32 *aClusterStarts); + NS_IMETHOD GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx); + NS_IMETHOD GetRangeWidth(const PRUnichar *aText, + PRUint32 aLength, + PRUint32 aStart, + PRUint32 aEnd, + PRUint32 &aWidth); + protected: virtual ~nsRenderingContextImpl(); --- mozilla/gfx/public/nsIRenderingContext.h.foo 2004-10-08 12:57:18.000000000 -0400 +++ mozilla/gfx/public/nsIRenderingContext.h 2004-12-16 13:13:31.000000000 -0500 @@ -824,6 +824,66 @@ NS_IMETHOD DrawTile(imgIContainer *aImage, 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. + * + * @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, + PRUint32 *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 aCoord The distance into the string to check. + * @param aInx Index of character where the cursor falls - note that + * this can be after the last character if the cursor happens to + * the right of the last character in the text! + * + */ + NS_IMETHOD GetPosition(const PRUnichar *aText, + PRUint32 aLength, + nscoord aCoord, + PRUint32 &aInx) = 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; + }; //modifiers for text rendering @@ -866,6 +926,12 @@ */ #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 + //flags for copy CopyOffScreenBits //when performing the blit, use the region, if any, --- mozilla/layout/html/base/src/nsTextFrame.cpp.foo 2004-10-08 09:39:27.000000000 -0400 +++ mozilla/layout/html/base/src/nsTextFrame.cpp 2004-12-16 13:14:23.000000000 -0500 @@ -2339,6 +2339,24 @@ #endif sdptr = sdptr->mNext; } + + /* + * 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); @@ -2361,37 +2379,55 @@ nscolor currentBKColor; PRBool isCurrentBKColorTransparent; -#ifdef IBMBIDI - if (currentlength > 0 - && NS_SUCCEEDED(aRenderingContext.GetWidth(currenttext, currentlength,newWidth)))//ADJUST FOR CHAR SPACING + if (currentlength > 0) { - - if (isRightToLeftOnBidiPlatform) - currentX -= newWidth; -#else // not IBMBIDI - if (NS_SUCCEEDED(aRenderingContext.GetWidth(currenttext, currentlength,newWidth)))//ADJUST FOR CHAR SPACING - { -#endif - if (iter.CurrentBackGroundColor(currentBKColor, &isCurrentBKColorTransparent) && !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 (iter.CurrentBackGroundColor(currentBKColor, &isCurrentBKColorTransparent) && !isPaginated) + {//DRAW RECT HERE!!! + if (!isCurrentBKColorTransparent) { + aRenderingContext.SetColor(currentBKColor); + aRenderingContext.FillRect(currentX, dy, newWidth, mRect.height); + } + currentFGColor = EnsureDifferentColors(currentFGColor, currentBKColor); } - currentFGColor = EnsureDifferentColors(currentFGColor, currentBKColor); + } + else { + newWidth = 0; } } - else - newWidth =0; - + else { + newWidth = 0; + } + + aRenderingContext.PushState(); + + nsRect rect(currentX, dy, newWidth, mRect.height); + PRBool ignore; + aRenderingContext.SetClipRect(rect, nsClipCombine_kIntersect, + ignore); + 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(ignore); + #ifdef IBMBIDI if (!isRightToLeftOnBidiPlatform) #endif @@ -3429,6 +3465,16 @@ PRInt32 textWidth = 0; PRUnichar* text = paintBuffer.mBuffer; + // See if the font backend will do all the hard work for us. + PRUint32 clusterHint = 0; + acx->GetHints(clusterHint); + clusterHint &= NS_RENDERING_HINT_TEXT_CLUSTERS; + if (clusterHint) { + PRUint32 tmpIndx = indx; + acx->GetPosition(text, textLength, aPoint.x - origin.x, tmpIndx); + indx = tmpIndx; + } + else { #ifdef IBMBIDI PRBool getReversedPos = PR_FALSE; PRUint8 level = 0; @@ -3465,6 +3511,7 @@ indx++; } } + } aContentOffset = indx + mContentOffset; //reusing wordBufMem @@ -3916,6 +3963,12 @@ } PRInt32* ip = indexBuffer.mBuffer; + nsAutoIndexBuffer 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 @@ -3981,8 +4034,32 @@ aPos->mContentOffset = 0; PRInt32 i; + // Fill in the cluster hint information, if it's available. + nsCOMPtr 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(paintBuffer.mBuffer, (PRUint32)textLength, (PRUint32 *)clusterBuffer.mBuffer); + } + else { + memset(clusterBuffer.mBuffer, 1, sizeof(PRInt32) * textLength); + } + 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; @@ -4033,14 +4110,39 @@ PRInt32 i; aPos->mContentOffset = mContentLength; - for (i = aPos->mStartOffset +1 - mContentOffset; i <= mContentLength; i++){ + // Fill in the cluster hint information, if it's available. + nsCOMPtr 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(paintBuffer.mBuffer, (PRUint32)textLength, (PRUint32 *)clusterBuffer.mBuffer); + } + else { + memset(clusterBuffer.mBuffer, 1, sizeof(PRInt32) * textLength); + } + + 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);