Bug 482138 [TSF] nsTextFrame has to draw composition string by TIP specified style r+sr=roc

This commit is contained in:
Masayuki Nakano 2009-04-23 12:27:12 +09:00
parent 257a5fc973
commit cfff67f8c9
11 changed files with 405 additions and 72 deletions

View File

@ -47,15 +47,17 @@ interface nsIContent;
class nsFrameSelection;
class nsIFrame;
class nsIPresShell;
struct nsTextRangeStyle;
struct nsPoint;
%}
[ptr] native nsFrameSelection(nsFrameSelection);
[ptr] native nsIFrame(nsIFrame);
[ptr] native nsIPresShell(nsIPresShell);
[ref] native constTextRangeStyleRef(const nsTextRangeStyle);
[ref] native nsPointRef(nsPoint);
[scriptable, uuid(b416c692-eeb8-4186-addd-c444e81b68e5)]
[scriptable, uuid(98552206-ad7a-4d2d-8ce3-b6fa2389298b)]
interface nsISelectionPrivate : nsISupports
{
const short ENDOFPRECEDINGLINE=0;
@ -118,5 +120,13 @@ interface nsISelectionPrivate : nsISupports
[noscript] nsFrameSelection getFrameSelection();
[noscript] void setAncestorLimiter(in nsIContent aContent);
/**
* Set the painting style for the range. The range must be a range in
* the selection. The textRangeStyle will be used by text frame
* when it is painting the selection.
*/
[noscript] void setTextRangeStyle(in nsIDOMRange range,
in constTextRangeStyleRef textRangeStyle);
};

View File

@ -41,10 +41,12 @@
#include "nsISupports.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsGUIEvent.h"
// {B13C4BD8-CB9F-4763-A020-E99ABC9C2803}
#define NS_IPRIVATETEXTRANGE_IID \
{0xb471ab41, 0x2a79, 0x11d3, \
{ 0x9e, 0xa4, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b } }
{ 0xb13c4bd8, 0xcb9f, 0x4763, \
{ 0xa0, 0x20, 0xe9, 0x9a, 0xbc, 0x9c, 0x28, 0x3 } }
class nsIPrivateTextRange : public nsISupports {
public:
@ -68,6 +70,8 @@ public:
NS_IMETHOD GetRangeType(PRUint16* aRangeType)=0;
NS_IMETHOD SetRangeType(PRUint16 aRangeType)=0;
NS_IMETHOD GetRangeStyle(nsTextRangeStyle* aTextRangeStyle)=0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIPrivateTextRange, NS_IPRIVATETEXTRANGE_IID)

View File

@ -73,9 +73,7 @@ nsDOMTextEvent::nsDOMTextEvent(nsPresContext* aPresContext,
for(i = 0; i < te->rangeCount; i++) {
nsRefPtr<nsPrivateTextRange> tempPrivateTextRange = new
nsPrivateTextRange(te->rangeArray[i].mStartOffset,
te->rangeArray[i].mEndOffset,
te->rangeArray[i].mRangeType);
nsPrivateTextRange(te->rangeArray[i]);
if (tempPrivateTextRange) {
mTextRange->AppendTextRange(tempPrivateTextRange);

View File

@ -38,10 +38,11 @@
#include "nsPrivateTextRange.h"
nsPrivateTextRange::nsPrivateTextRange(PRUint16 aRangeStart, PRUint16 aRangeEnd, PRUint16 aRangeType)
: mRangeStart(aRangeStart),
mRangeEnd(aRangeEnd),
mRangeType(aRangeType)
nsPrivateTextRange::nsPrivateTextRange(const nsTextRange &aTextRange)
: mRangeStart(PRUint16(aTextRange.mStartOffset)),
mRangeEnd(PRUint16(aTextRange.mEndOffset)),
mRangeType(PRUint16(aTextRange.mRangeType)),
mRangeStyle(aTextRange.mRangeStyle)
{
}
@ -87,6 +88,13 @@ NS_METHOD nsPrivateTextRange::SetRangeType(PRUint16 aRangeType)
return NS_OK;
}
NS_METHOD nsPrivateTextRange::GetRangeStyle(nsTextRangeStyle* aTextRangeStyle)
{
NS_ENSURE_ARG_POINTER(aTextRangeStyle);
*aTextRangeStyle = mRangeStyle;
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsPrivateTextRangeList, nsIPrivateTextRangeList)
void nsPrivateTextRangeList::AppendTextRange(nsRefPtr<nsPrivateTextRange>& aRange)

View File

@ -47,7 +47,7 @@ class nsPrivateTextRange : public nsIPrivateTextRange
NS_DECL_ISUPPORTS
public:
nsPrivateTextRange(PRUint16 aRangeStart, PRUint16 aRangeEnd, PRUint16 aRangeType);
nsPrivateTextRange(const nsTextRange &aTextRange);
virtual ~nsPrivateTextRange(void);
NS_IMETHOD GetRangeStart(PRUint16* aRangeStart);
@ -59,11 +59,14 @@ public:
NS_IMETHOD GetRangeType(PRUint16* aRangeType);
NS_IMETHOD SetRangeType(PRUint16 aRangeType);
NS_IMETHOD GetRangeStyle(nsTextRangeStyle* aRangeStyle);
protected:
PRUint16 mRangeStart;
PRUint16 mRangeEnd;
PRUint16 mRangeType;
nsTextRangeStyle mRangeStyle;
};
class nsPrivateTextRangeList: public nsIPrivateTextRangeList

View File

@ -337,21 +337,38 @@ NS_IMETHODIMP IMETextTxn::CollapseTextSelection(void)
if(NS_FAILED(result))
break;
newRange->SetStart(mElement,mOffset+selectionStart);
result = newRange->SetStart(mElement,mOffset+selectionStart);
NS_ASSERTION(NS_SUCCEEDED(result), "Cannot SetStart");
if(NS_FAILED(result))
break;
newRange->SetEnd(mElement,mOffset+selectionEnd);
result = newRange->SetEnd(mElement,mOffset+selectionEnd);
NS_ASSERTION(NS_SUCCEEDED(result), "Cannot SetEnd");
if(NS_FAILED(result))
break;
imeSel->AddRange(newRange);
result = imeSel->AddRange(newRange);
NS_ASSERTION(NS_SUCCEEDED(result), "Cannot AddRange");
if(NS_FAILED(result))
break;
nsCOMPtr<nsISelectionPrivate> imeSelPriv(
do_QueryInterface(imeSel));
if (imeSelPriv) {
nsTextRangeStyle textRangeStyle;
result = textRange->GetRangeStyle(&textRangeStyle);
NS_ASSERTION(NS_SUCCEEDED(result),
"nsIPrivateTextRange::GetRangeStyle failed");
if (NS_FAILED(result))
break;
result = imeSelPriv->SetTextRangeStyle(newRange, textRangeStyle);
NS_ASSERTION(NS_SUCCEEDED(result),
"nsISelectionPrivate::SetTextRangeStyle failed");
if (NS_FAILED(result))
break;
} else {
NS_WARNING("IME selection doesn't have nsISelectionPrivate");
}
} // if GetRangeEnd
} // for textRangeListLength
if(! setCaret) {

View File

@ -49,10 +49,10 @@
#include "nsIRange.h"
// IID for the nsFrameSelection interface
// d78edc5a-28d0-48f0-8abb-1597b1591556
// 0ea74459-e3f9-48b0-8aa4-5dfef53bf1f7
#define NS_FRAME_SELECTION_IID \
{ 0xd78edc5a, 0x28d0, 0x48f0, \
{ 0x8a, 0xbb, 0x15, 0x97, 0xb1, 0x59, 0x15, 0x56 } }
{ 0xea74459, 0xe3f9, 0x48b0, \
{ 0x8a, 0xa4, 0x5d, 0xfe, 0xf5, 0x3b, 0xf1, 0xf7 } }
#ifdef IBMBIDI // Constant for Set/Get CaretBidiLevel
#define BIDI_LEVEL_UNDEFINED 0x80
@ -75,6 +75,7 @@ struct SelectionDetails
PRInt32 mStart;
PRInt32 mEnd;
SelectionType mType;
nsTextRangeStyle mTextRangeStyle;
SelectionDetails *mNext;
};

View File

@ -164,6 +164,7 @@ struct RangeData
nsCOMPtr<nsIRange> mRange;
PRInt32 mEndIndex; // index into mRangeEndings of this item
nsTextRangeStyle mTextRangeStyle;
};
static RangeData sEmptyData(nsnull, 0);
@ -357,6 +358,7 @@ private:
nsINode* aEndNode, PRInt32 aEndOffset,
PRBool aAllowAdjacent,
nsCOMArray<nsIRange>* aRanges);
RangeData* FindRangeData(nsIDOMRange* aRange);
nsTArray<RangeData> mRanges;
nsTArray<PRInt32> mRangeEndings; // references info mRanges
@ -4542,6 +4544,10 @@ nsTypedSelection::LookUpSelection(nsIContent *aContent, PRInt32 aContentOffset,
details->mStart = start;
details->mEnd = end;
details->mType = aType;
RangeData *rd = FindRangeData(range);
if (rd) {
details->mTextRangeStyle = rd->mTextRangeStyle;
}
*aReturnDetails = details;
}
return NS_OK;
@ -4647,6 +4653,29 @@ nsTypedSelection::SetAncestorLimiter(nsIContent *aContent)
return NS_OK;
}
RangeData*
nsTypedSelection::FindRangeData(nsIDOMRange* aRange)
{
NS_ENSURE_TRUE(aRange, nsnull);
for (PRUint32 i = 0; i < mRanges.Length(); i++) {
if (mRanges[i].mRange == aRange)
return &mRanges[i];
}
return nsnull;
}
NS_IMETHODIMP
nsTypedSelection::SetTextRangeStyle(nsIDOMRange *aRange,
const nsTextRangeStyle &aTextRangeStyle)
{
NS_ENSURE_ARG_POINTER(aRange);
RangeData *rd = FindRangeData(aRange);
if (rd) {
rd->mTextRangeStyle = aTextRangeStyle;
}
return NS_OK;
}
nsresult
nsTypedSelection::StartAutoScrollTimer(nsPresContext *aPresContext,
nsIView *aView,

View File

@ -4090,23 +4090,58 @@ static const SelectionType SelectionTypesWithDecorations =
nsISelectionController::SELECTION_IME_CONVERTEDTEXT |
nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT;
static PRUint8
GetTextDecorationStyle(const nsTextRangeStyle &aRangeStyle)
{
NS_PRECONDITION(aRangeStyle.IsLineStyleDefined(),
"aRangeStyle.mLineStyle have to be defined");
switch (aRangeStyle.mLineStyle) {
case nsTextRangeStyle::LINESTYLE_NONE:
return nsCSSRendering::DECORATION_STYLE_NONE;
case nsTextRangeStyle::LINESTYLE_SOLID:
return nsCSSRendering::DECORATION_STYLE_SOLID;
case nsTextRangeStyle::LINESTYLE_DOTTED:
return nsCSSRendering::DECORATION_STYLE_DOTTED;
case nsTextRangeStyle::LINESTYLE_DASHED:
return nsCSSRendering::DECORATION_STYLE_DASHED;
case nsTextRangeStyle::LINESTYLE_DOUBLE:
return nsCSSRendering::DECORATION_STYLE_DOUBLE;
case nsTextRangeStyle::LINESTYLE_WAVY:
return nsCSSRendering::DECORATION_STYLE_WAVY;
default:
NS_WARNING("Requested underline style is not valid");
return nsCSSRendering::DECORATION_STYLE_SOLID;
}
}
/**
* This, plus SelectionTypesWithDecorations, encapsulates all knowledge about
* drawing text decoration for selections.
*/
static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
nsTextPaintStyle& aTextPaintStyle, const gfxPoint& aPt, gfxFloat aWidth,
nsTextPaintStyle& aTextPaintStyle,
const nsTextRangeStyle &aRangeStyle,
const gfxPoint& aPt, gfxFloat aWidth,
gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics)
{
gfxPoint pt(aPt);
gfxSize size(aWidth, aFontMetrics.underlineSize);
gfxFloat descentLimit = aFontMetrics.maxDescent;
float relativeSize;
PRUint8 style;
nscolor color;
PRInt32 index =
nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(aType);
PRBool weDefineSelectionUnderline =
aTextPaintStyle.GetSelectionUnderlineForPaint(index, &color,
&relativeSize, &style);
switch (aType) {
case nsISelectionController::SELECTION_IME_RAWINPUT:
case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT:
case nsISelectionController::SELECTION_IME_CONVERTEDTEXT:
case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT:
case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT: {
// IME decoration lines should not be drawn on the both ends, i.e., we
// need to cut both edges of the decoration lines. Because same style
// IME selections can adjoin, but the users need to be able to know
@ -4122,26 +4157,46 @@ static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
// gap gap gap
pt.x += 1.0;
size.width -= 2.0;
case nsISelectionController::SELECTION_SPELLCHECK: {
float relativeSize;
PRUint8 style;
nscolor color;
PRInt32 index =
nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(aType);
if (aTextPaintStyle.GetSelectionUnderlineForPaint(index, &color,
&relativeSize,
&style)) {
size.height *= relativeSize;
nsCSSRendering::PaintDecorationLine(
aContext, color, pt, size, aAscent, aFontMetrics.underlineOffset,
NS_STYLE_TEXT_DECORATION_UNDERLINE, style, descentLimit);
if (aRangeStyle.IsDefined()) {
// If IME defines the style, that should override our definition.
if (aRangeStyle.IsLineStyleDefined()) {
if (aRangeStyle.mLineStyle == nsTextRangeStyle::LINESTYLE_NONE) {
return;
}
style = GetTextDecorationStyle(aRangeStyle);
relativeSize = aRangeStyle.mIsBoldLine ? 2.0f : 1.0f;
} else if (!weDefineSelectionUnderline) {
// There is no underline style definition.
return;
}
if (aRangeStyle.IsUnderlineColorDefined()) {
color = aRangeStyle.mUnderlineColor;
} else if (aRangeStyle.IsForegroundColorDefined()) {
color = aRangeStyle.mForegroundColor;
} else {
NS_ASSERTION(!aRangeStyle.IsBackgroundColorDefined(),
"Only the background color is defined");
color = aTextPaintStyle.GetTextColor();
}
} else if (!weDefineSelectionUnderline) {
// IME doesn't specify the selection style and we don't define selection
// underline.
return;
}
break;
}
case nsISelectionController::SELECTION_SPELLCHECK:
if (!weDefineSelectionUnderline)
return;
break;
default:
NS_WARNING("Requested selection decorations when there aren't any");
break;
return;
}
size.height *= relativeSize;
nsCSSRendering::PaintDecorationLine(
aContext, color, pt, size, aAscent, aFontMetrics.underlineOffset,
NS_STYLE_TEXT_DECORATION_UNDERLINE, style, descentLimit);
}
/**
@ -4152,7 +4207,9 @@ static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
* @param aBackground the background color to use, or RGBA(0,0,0,0) if no
* background should be painted
*/
static PRBool GetSelectionTextColors(SelectionType aType, nsTextPaintStyle& aTextPaintStyle,
static PRBool GetSelectionTextColors(SelectionType aType,
nsTextPaintStyle& aTextPaintStyle,
const nsTextRangeStyle &aRangeStyle,
nscolor* aForeground, nscolor* aBackground)
{
switch (aType) {
@ -4165,11 +4222,25 @@ static PRBool GetSelectionTextColors(SelectionType aType, nsTextPaintStyle& aTex
case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT:
case nsISelectionController::SELECTION_IME_CONVERTEDTEXT:
case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT:
if (aRangeStyle.IsDefined()) {
*aForeground = aTextPaintStyle.GetTextColor();
*aBackground = NS_RGBA(0,0,0,0);
if (!aRangeStyle.IsForegroundColorDefined() &&
!aRangeStyle.IsBackgroundColorDefined()) {
return PR_FALSE;
}
if (aRangeStyle.IsForegroundColorDefined()) {
*aForeground = aRangeStyle.mForegroundColor;
}
if (aRangeStyle.IsBackgroundColorDefined()) {
*aBackground = aRangeStyle.mBackgroundColor;
}
return PR_TRUE;
}
aTextPaintStyle.GetIMESelectionColors(
nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(aType),
aForeground, aBackground);
return PR_TRUE;
default:
*aForeground = aTextPaintStyle.GetTextColor();
*aBackground = NS_RGBA(0,0,0,0);
@ -4187,13 +4258,13 @@ static PRBool GetSelectionTextColors(SelectionType aType, nsTextPaintStyle& aTex
class SelectionIterator {
public:
/**
* aStart and aLength are in the original string. aSelectionBuffer is
* aStart and aLength are in the original string. aSelectionDetails is
* according to the original string.
*/
SelectionIterator(SelectionType* aSelectionBuffer, PRInt32 aStart,
PRInt32 aLength, PropertyProvider& aProvider,
gfxTextRun* aTextRun);
SelectionIterator(SelectionDetails** aSelectionDetails,
PRInt32 aStart, PRInt32 aLength,
PropertyProvider& aProvider, gfxTextRun* aTextRun);
/**
* Returns the next segment of uniformly selected (or not) text.
* @param aXOffset the offset from the origin of the frame to the start
@ -4204,16 +4275,18 @@ public:
* @param aHyphenWidth if a hyphen is to be rendered after the text, the
* width of the hyphen, otherwise zero
* @param aType the selection type for this segment
* @param aStyle the selection style for this segment
* @return false if there are no more segments
*/
PRBool GetNextSegment(gfxFloat* aXOffset, PRUint32* aOffset, PRUint32* aLength,
gfxFloat* aHyphenWidth, SelectionType* aType);
gfxFloat* aHyphenWidth, SelectionType* aType,
nsTextRangeStyle* aStyle);
void UpdateWithAdvance(gfxFloat aAdvance) {
mXOffset += aAdvance*mTextRun->GetDirection();
}
private:
SelectionType* mSelectionBuffer;
SelectionDetails** mSelectionDetails;
PropertyProvider& mProvider;
gfxTextRun* mTextRun;
gfxSkipCharsIterator mIterator;
@ -4222,10 +4295,10 @@ private:
gfxFloat mXOffset;
};
SelectionIterator::SelectionIterator(SelectionType* aSelectionBuffer,
SelectionIterator::SelectionIterator(SelectionDetails** aSelectionDetails,
PRInt32 aStart, PRInt32 aLength, PropertyProvider& aProvider,
gfxTextRun* aTextRun)
: mSelectionBuffer(aSelectionBuffer), mProvider(aProvider),
: mSelectionDetails(aSelectionDetails), mProvider(aProvider),
mTextRun(aTextRun), mIterator(aProvider.GetStart()),
mOriginalStart(aStart), mOriginalEnd(aStart + aLength),
mXOffset(mTextRun->IsRightToLeft() ? aProvider.GetFrame()->GetSize().width : 0)
@ -4234,7 +4307,8 @@ SelectionIterator::SelectionIterator(SelectionType* aSelectionBuffer,
}
PRBool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
PRUint32* aOffset, PRUint32* aLength, gfxFloat* aHyphenWidth, SelectionType* aType)
PRUint32* aOffset, PRUint32* aLength, gfxFloat* aHyphenWidth,
SelectionType* aType, nsTextRangeStyle* aStyle)
{
if (mIterator.GetOriginalOffset() >= mOriginalEnd)
return PR_FALSE;
@ -4243,13 +4317,19 @@ PRBool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
PRUint32 runOffset = mIterator.GetSkippedOffset();
PRInt32 index = mIterator.GetOriginalOffset() - mOriginalStart;
SelectionType type = mSelectionBuffer[index];
SelectionDetails* sdptr = mSelectionDetails[index];
SelectionType type =
sdptr ? sdptr->mType : nsISelectionController::SELECTION_NONE;
nsTextRangeStyle style;
if (sdptr) {
style = sdptr->mTextRangeStyle;
}
for (++index; mOriginalStart + index < mOriginalEnd; ++index) {
if (mSelectionBuffer[index] != type)
if (sdptr != mSelectionDetails[index])
break;
}
mIterator.SetOriginalOffset(index + mOriginalStart);
// Advance to the next cluster boundary
while (mIterator.GetOriginalOffset() < mOriginalEnd &&
!mIterator.IsOriginalCharSkipped() &&
@ -4267,6 +4347,7 @@ PRBool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
*aHyphenWidth = mProvider.GetHyphenWidth();
}
*aType = type;
*aStyle = style;
return PR_TRUE;
}
@ -4362,14 +4443,15 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
PRInt32 contentLength = aProvider.GetOriginalLength();
// Figure out which selections control the colors to use for each character.
nsAutoTArray<SelectionType,BIG_TEXT_NODE_SIZE> prevailingSelectionsBuffer;
nsAutoTArray<SelectionDetails*,BIG_TEXT_NODE_SIZE> prevailingSelectionsBuffer;
if (!prevailingSelectionsBuffer.AppendElements(contentLength))
return;
SelectionType* prevailingSelections = prevailingSelectionsBuffer.Elements();
SelectionDetails** prevailingSelections = prevailingSelectionsBuffer.Elements();
PRInt32 i;
SelectionType allTypes = 0;
for (i = 0; i < contentLength; ++i) {
prevailingSelections[i] = nsISelectionController::SELECTION_NONE;
prevailingSelections[i] = nsnull;
}
SelectionDetails *sdptr = aDetails;
@ -4382,16 +4464,16 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
allTypes |= type;
// Ignore selections that don't set colors
nscolor foreground, background;
if (GetSelectionTextColors(type, aTextPaintStyle, &foreground, &background)) {
if (GetSelectionTextColors(type, aTextPaintStyle, sdptr->mTextRangeStyle,
&foreground, &background)) {
if (NS_GET_A(background) > 0) {
anyBackgrounds = PR_TRUE;
}
for (i = start; i < end; ++i) {
PRInt16 currentPrevailingSelection = prevailingSelections[i];
// Favour normal selection over IME selections
if (currentPrevailingSelection == nsISelectionController::SELECTION_NONE ||
type < currentPrevailingSelection) {
prevailingSelections[i] = type;
if (!prevailingSelections[i] ||
type < prevailingSelections[i]->mType) {
prevailingSelections[i] = sdptr;
}
}
}
@ -4403,13 +4485,16 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
gfxFloat xOffset, hyphenWidth;
PRUint32 offset, length; // in transformed string
SelectionType type;
nsTextRangeStyle rangeStyle;
// Draw background colors
if (anyBackgrounds) {
SelectionIterator iterator(prevailingSelections, contentOffset, contentLength,
aProvider, mTextRun);
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth, &type)) {
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth,
&type, &rangeStyle)) {
nscolor foreground, background;
GetSelectionTextColors(type, aTextPaintStyle, &foreground, &background);
GetSelectionTextColors(type, aTextPaintStyle, rangeStyle,
&foreground, &background);
// Draw background color
gfxFloat advance = hyphenWidth +
mTextRun->GetAdvanceWidth(offset, length, &aProvider);
@ -4426,9 +4511,11 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
// Draw text
SelectionIterator iterator(prevailingSelections, contentOffset, contentLength,
aProvider, mTextRun);
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth, &type)) {
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth,
&type, &rangeStyle)) {
nscolor foreground, background;
GetSelectionTextColors(type, aTextPaintStyle, &foreground, &background);
GetSelectionTextColors(type, aTextPaintStyle, rangeStyle,
&foreground, &background);
// Draw text segment
aCtx->SetColor(gfxRGBA(foreground));
gfxFloat advance;
@ -4453,15 +4540,14 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
PRInt32 contentOffset = aProvider.GetStart().GetOriginalOffset();
PRInt32 contentLength = aProvider.GetOriginalLength();
// Figure out which characters will be decorated for this selection. Here
// we just fill the buffer with either SELECTION_NONE or aSelectionType.
nsAutoTArray<SelectionType,BIG_TEXT_NODE_SIZE> selectedCharsBuffer;
// Figure out which characters will be decorated for this selection.
nsAutoTArray<SelectionDetails*, BIG_TEXT_NODE_SIZE> selectedCharsBuffer;
if (!selectedCharsBuffer.AppendElements(contentLength))
return;
SelectionType* selectedChars = selectedCharsBuffer.Elements();
SelectionDetails** selectedChars = selectedCharsBuffer.Elements();
PRInt32 i;
for (i = 0; i < contentLength; ++i) {
selectedChars[i] = nsISelectionController::SELECTION_NONE;
selectedChars[i] = nsnull;
}
SelectionDetails *sdptr = aDetails;
@ -4470,7 +4556,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
PRInt32 start = PR_MAX(0, sdptr->mStart - contentOffset);
PRInt32 end = PR_MIN(contentLength, sdptr->mEnd - contentOffset);
for (i = start; i < end; ++i) {
selectedChars[i] = aSelectionType;
selectedChars[i] = sdptr;
}
}
sdptr = sdptr->mNext;
@ -4491,7 +4577,9 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
// XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint?
gfxPoint pt(0.0, (aTextBaselinePt.y - mAscent) / app);
SelectionType type;
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth, &type)) {
nsTextRangeStyle selectedStyle;
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth,
&type, &selectedStyle)) {
gfxFloat advance = hyphenWidth +
mTextRun->GetAdvanceWidth(offset, length, &aProvider);
if (type == aSelectionType) {
@ -4499,6 +4587,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
gfxFloat width = PR_ABS(advance) / app;
DrawSelectionDecorations(aCtx, aSelectionType, aTextPaintStyle,
selectedStyle,
pt, width, mAscent / app, decorationMetrics);
}
iterator.UpdateWithAdvance(advance);
@ -4799,9 +4888,26 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
float relativeSize;
PRInt32 index =
nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(sd->mType);
if (!nsTextPaintStyle::GetSelectionUnderline(aPresContext, index, nsnull,
&relativeSize, &style)) {
continue;
if (sd->mType == nsISelectionController::SELECTION_SPELLCHECK) {
if (!nsTextPaintStyle::GetSelectionUnderline(aPresContext, index, nsnull,
&relativeSize, &style)) {
continue;
}
} else {
// IME selections
nsTextRangeStyle& rangeStyle = sd->mTextRangeStyle;
if (rangeStyle.IsDefined()) {
if (!rangeStyle.IsLineStyleDefined() ||
rangeStyle.mLineStyle == nsTextRangeStyle::LINESTYLE_NONE) {
continue;
}
style = GetTextDecorationStyle(rangeStyle);
relativeSize = rangeStyle.mIsBoldLine ? 2.0f : 1.0f;
} else if (!nsTextPaintStyle::GetSelectionUnderline(aPresContext, index,
nsnull, &relativeSize,
&style)) {
continue;
}
}
nsRect decorationArea;
gfxSize size(aPresContext->AppUnitsToGfxUnits(aRect.width),

View File

@ -843,6 +843,96 @@ public:
/**
* IME Related Events
*/
struct nsTextRangeStyle
{
enum {
LINESTYLE_NONE = 0,
LINESTYLE_SOLID = 1,
LINESTYLE_DOTTED = 2,
LINESTYLE_DASHED = 3,
LINESTYLE_DOUBLE = 4,
LINESTYLE_WAVY = 5
};
enum {
DEFINED_NONE = 0x00,
DEFINED_LINESTYLE = 0x01,
DEFINED_FOREGROUND_COLOR = 0x02,
DEFINED_BACKGROUND_COLOR = 0x04,
DEFINED_UNDERLINE_COLOR = 0x08
};
// Initialize all members, because nsTextRange instances may be compared by
// memcomp.
nsTextRangeStyle() :
mDefinedStyles(DEFINED_NONE), mLineStyle(LINESTYLE_NONE),
mIsBoldLine(PR_FALSE), mForegroundColor(NS_RGBA(0, 0, 0, 0)),
mBackgroundColor(NS_RGBA(0, 0, 0, 0)), mUnderlineColor(NS_RGBA(0, 0, 0, 0))
{
}
PRBool IsDefined() const { return mDefinedStyles != DEFINED_NONE; }
PRBool IsLineStyleDefined() const
{
return (mDefinedStyles & DEFINED_LINESTYLE) != 0;
}
PRBool IsForegroundColorDefined() const
{
return (mDefinedStyles & DEFINED_FOREGROUND_COLOR) != 0;
}
PRBool IsBackgroundColorDefined() const
{
return (mDefinedStyles & DEFINED_BACKGROUND_COLOR) != 0;
}
PRBool IsUnderlineColorDefined() const
{
return (mDefinedStyles & DEFINED_UNDERLINE_COLOR) != 0;
}
PRBool Equals(const nsTextRangeStyle& aOther)
{
if (mDefinedStyles != aOther.mDefinedStyles)
return PR_FALSE;
if (IsLineStyleDefined() && (mLineStyle != aOther.mLineStyle ||
!mIsBoldLine != !aOther.mIsBoldLine))
return PR_FALSE;
if (IsForegroundColorDefined() &&
(mForegroundColor != aOther.mForegroundColor))
return PR_FALSE;
if (IsBackgroundColorDefined() &&
(mBackgroundColor != aOther.mBackgroundColor))
return PR_FALSE;
if (IsUnderlineColorDefined() &&
(mUnderlineColor != aOther.mUnderlineColor))
return PR_FALSE;
return PR_TRUE;
}
PRBool operator !=(const nsTextRangeStyle &aOther)
{
return !Equals(aOther);
}
PRBool operator ==(const nsTextRangeStyle &aOther)
{
return Equals(aOther);
}
PRUint8 mDefinedStyles;
PRUint8 mLineStyle; // DEFINED_LINESTYLE
PRPackedBool mIsBoldLine; // DEFINED_LINESTYLE
nscolor mForegroundColor; // DEFINED_FOREGROUND_COLOR
nscolor mBackgroundColor; // DEFINED_BACKGROUND_COLOR
nscolor mUnderlineColor; // DEFINED_UNDERLINE_COLOR
};
struct nsTextRange
{
nsTextRange()
@ -853,6 +943,8 @@ struct nsTextRange
PRUint32 mStartOffset;
PRUint32 mEndOffset;
PRUint32 mRangeType;
nsTextRangeStyle mRangeStyle;
};
typedef nsTextRange* nsTextRangeArray;

View File

@ -621,6 +621,50 @@ nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew)
return S_OK;
}
static PRBool
GetColor(const TF_DA_COLOR &aTSFColor, nscolor &aResult)
{
switch (aTSFColor.type) {
case TF_CT_SYSCOLOR: {
DWORD sysColor = ::GetSysColor(aTSFColor.nIndex);
aResult = NS_RGB(GetRValue(sysColor), GetGValue(sysColor),
GetBValue(sysColor));
return PR_TRUE;
}
case TF_CT_COLORREF:
aResult = NS_RGB(GetRValue(aTSFColor.cr), GetGValue(aTSFColor.cr),
GetBValue(aTSFColor.cr));
return PR_TRUE;
case TF_CT_NONE:
default:
return PR_FALSE;
}
}
static PRBool
GetLineStyle(TF_DA_LINESTYLE aTSFLineStyle, PRUint8 &aTextRangeLineStyle)
{
switch (aTSFLineStyle) {
case TF_LS_NONE:
aTextRangeLineStyle = nsTextRangeStyle::LINESTYLE_NONE;
return PR_TRUE;
case TF_LS_SOLID:
aTextRangeLineStyle = nsTextRangeStyle::LINESTYLE_SOLID;
return PR_TRUE;
case TF_LS_DOT:
aTextRangeLineStyle = nsTextRangeStyle::LINESTYLE_DOTTED;
return PR_TRUE;
case TF_LS_DASH:
aTextRangeLineStyle = nsTextRangeStyle::LINESTYLE_DASHED;
return PR_TRUE;
case TF_LS_SQUIGGLE:
aTextRangeLineStyle = nsTextRangeStyle::LINESTYLE_WAVY;
return PR_TRUE;
default:
return PR_FALSE;
}
}
HRESULT
nsTextStore::SendTextEventForCompositionString()
{
@ -677,6 +721,7 @@ nsTextStore::SendTextEventForCompositionString()
if (FAILED(GetRangeExtent(range, &start, &length)))
continue;
nsTextRange newRange;
newRange.mStartOffset = PRUint32(start - mCompositionStart);
// The end of the last range in the array is
// always kept at the end of composition
@ -684,8 +729,28 @@ nsTextStore::SendTextEventForCompositionString()
TF_DISPLAYATTRIBUTE attr;
hr = GetDisplayAttribute(attrPropetry, range, &attr);
newRange.mRangeType =
SUCCEEDED(hr) ? GetGeckoSelectionValue(attr) : NS_TEXTRANGE_RAWINPUT;
if (FAILED(hr)) {
newRange.mRangeType = NS_TEXTRANGE_RAWINPUT;
} else {
newRange.mRangeType = GetGeckoSelectionValue(attr);
if (GetColor(attr.crText, newRange.mRangeStyle.mForegroundColor)) {
newRange.mRangeStyle.mDefinedStyles |=
nsTextRangeStyle::DEFINED_FOREGROUND_COLOR;
}
if (GetColor(attr.crBk, newRange.mRangeStyle.mBackgroundColor)) {
newRange.mRangeStyle.mDefinedStyles |=
nsTextRangeStyle::DEFINED_BACKGROUND_COLOR;
}
if (GetColor(attr.crLine, newRange.mRangeStyle.mUnderlineColor)) {
newRange.mRangeStyle.mDefinedStyles |=
nsTextRangeStyle::DEFINED_UNDERLINE_COLOR;
}
if (GetLineStyle(attr.lsStyle, newRange.mRangeStyle.mLineStyle)) {
newRange.mRangeStyle.mDefinedStyles |=
nsTextRangeStyle::DEFINED_LINESTYLE;
newRange.mRangeStyle.mIsBoldLine = attr.fBoldLine != 0;
}
}
nsTextRange& lastRange = textRanges[textRanges.Length() - 1];
if (lastRange.mStartOffset == newRange.mStartOffset) {