зеркало из https://github.com/mozilla/pjs.git
bug 348901. Remove extra whitespace from source when exposing accessible text. r+sr=roc, r=surkov. a=dbaron
This commit is contained in:
Родитель
95f65866c6
Коммит
58bbdf1368
|
@ -79,6 +79,7 @@ endif
|
|||
|
||||
EXTRA_DSO_LIBS = \
|
||||
gkgfx \
|
||||
thebes \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
interface nsIAccessible;
|
||||
interface nsIAccessibleEvent;
|
||||
|
||||
[uuid(817ae493-b238-4fbc-a623-d20ed81eebcd)]
|
||||
[uuid(03932812-53d1-4dc7-965d-6b6ad8a872b1)]
|
||||
interface nsPIAccessible : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -100,6 +100,7 @@ interface nsPIAccessible : nsISupports
|
|||
* Returns text of accessible if accessible has text role otherwise empty
|
||||
* string.
|
||||
*/
|
||||
AString getContentText();
|
||||
void appendTextTo(out AString aString, in unsigned long aStartOffset,
|
||||
in unsigned long aLength);
|
||||
};
|
||||
|
||||
|
|
|
@ -1519,12 +1519,13 @@ nsresult nsAccessible::AppendFlatStringFromContentNode(nsIContent *aContent, nsA
|
|||
}
|
||||
}
|
||||
if (aContent->TextLength() > 0) {
|
||||
nsAutoString text;
|
||||
aContent->AppendTextTo(text);
|
||||
if (!text.IsEmpty())
|
||||
aFlatString->Append(text);
|
||||
if (isHTMLBlock && !aFlatString->IsEmpty())
|
||||
nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
nsresult rv = frame->GetRenderedText(aFlatString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isHTMLBlock && !aFlatString->IsEmpty()) {
|
||||
aFlatString->Append(PRUnichar(' '));
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3147,18 +3148,34 @@ PRInt32 nsAccessible::TextLength(nsIAccessible *aAccessible)
|
|||
if (!IsText(aAccessible))
|
||||
return 1;
|
||||
|
||||
nsCOMPtr<nsPIAccessNode> pAccNode(do_QueryInterface(aAccessible));
|
||||
NS_ASSERTION(pAccNode, "QI to nsPIAccessNode failed");
|
||||
|
||||
nsIFrame *frame = pAccNode->GetFrame();
|
||||
if (frame) { // Optimal way to get the text length -- no string copy
|
||||
nsIContent *content = frame->GetContent();
|
||||
if (content) {
|
||||
PRUint32 length;
|
||||
nsresult rv = nsHyperTextAccessible::ContentToRenderedOffset(frame, content->TextLength(), &length);
|
||||
return NS_SUCCEEDED(rv) ? length : -1;
|
||||
}
|
||||
}
|
||||
|
||||
// For list bullets (or anything other accessible which would compute its own text
|
||||
// They don't have their own frame.
|
||||
// XXX In the future, list bullets may have frame and anon content, so
|
||||
// we should be able to remove this at that point
|
||||
nsCOMPtr<nsPIAccessible> pAcc(do_QueryInterface(aAccessible));
|
||||
NS_ENSURE_TRUE(pAcc, NS_ERROR_FAILURE);
|
||||
NS_ASSERTION(pAcc, "QI to nsPIAccessible failed");
|
||||
|
||||
nsAutoString text;
|
||||
pAcc->GetContentText(text);
|
||||
pAcc->AppendTextTo(text, 0, PR_UINT32_MAX); // Get all the text
|
||||
return text.Length();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAccessible::GetContentText(nsAString& aText)
|
||||
nsAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength)
|
||||
{
|
||||
aText.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ public:
|
|||
static PRUint32 Role(nsIAccessible *aAcc) { PRUint32 role; aAcc->GetFinalRole(&role); return role; }
|
||||
static PRBool IsText(nsIAccessible *aAcc) { PRUint32 role = Role(aAcc); return role == nsIAccessibleRole::ROLE_TEXT_LEAF || role == nsIAccessibleRole::ROLE_STATICTEXT; }
|
||||
static PRBool IsEmbeddedObject(nsIAccessible *aAcc) { PRUint32 role = Role(aAcc); return role != nsIAccessibleRole::ROLE_TEXT_LEAF && role != nsIAccessibleRole::ROLE_WHITESPACE && role != nsIAccessibleRole::ROLE_STATICTEXT; }
|
||||
static PRInt32 TextLength(nsIAccessible *aAccessible);
|
||||
static PRInt32 TextLength(nsIAccessible *aAccessible); // Returns -1 on failure
|
||||
static PRBool IsLeaf(nsIAccessible *aAcc) { PRInt32 numChildren; aAcc->GetChildCount(&numChildren); return numChildren > 0; }
|
||||
static PRBool IsNodeRelevant(nsIDOMNode *aNode); // Is node something that could have an attached accessible
|
||||
|
||||
|
|
|
@ -1208,7 +1208,7 @@ nsDocAccessible::FireTextChangedEventOnDOMCharacterDataModified(nsIContent *aCon
|
|||
PRUint32 replaceLen = aInfo->mReplaceLength;
|
||||
|
||||
PRInt32 offset = 0;
|
||||
rv = textAccessible->DOMPointToOffset(node, start, &offset);
|
||||
rv = textAccessible->DOMPointToHypertextOffset(node, start, &offset);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
|
@ -1269,7 +1269,7 @@ nsDocAccessible::FireTextChangedEventOnDOMNodeInserted(nsIContent *aChild,
|
|||
return;
|
||||
|
||||
PRInt32 offset = 0;
|
||||
rv = textAccessible->DOMPointToOffset(parentNode, aIndexInContainer, &offset);
|
||||
rv = textAccessible->DOMPointToHypertextOffset(parentNode, aIndexInContainer, &offset);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
|
@ -1323,7 +1323,7 @@ nsDocAccessible::FireTextChangedEventOnDOMNodeRemoved(nsIContent *aChild,
|
|||
return;
|
||||
|
||||
PRInt32 offset = 0;
|
||||
rv = textAccessible->DOMPointToOffset(parentNode, aIndexInContainer, &offset);
|
||||
rv = textAccessible->DOMPointToHypertextOffset(parentNode, aIndexInContainer, &offset);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
|
|
|
@ -89,16 +89,11 @@ NS_IMETHODIMP nsTextAccessible::GetChildCount(PRInt32 *_retval)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextAccessible::GetContentText(nsAString& aText)
|
||||
nsTextAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength)
|
||||
{
|
||||
nsresult rv = nsLinkableAccessible::GetContentText(aText);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIFrame *frame = GetFrame();
|
||||
if (!frame)
|
||||
return NS_OK;
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
frame->GetContent()->AppendTextTo(aText);
|
||||
return NS_OK;
|
||||
return frame->GetRenderedText(&aText, nsnull, nsnull, aStartOffset, aLength);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
NS_IMETHOD GetChildCount(PRInt32 *_retval);
|
||||
|
||||
// nsPIAccessible
|
||||
NS_IMETHOD GetContentText(nsAString& aText);
|
||||
NS_IMETHOD AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ REQUIRES = content \
|
|||
locale \
|
||||
necko \
|
||||
string \
|
||||
thebes \
|
||||
webshell \
|
||||
widget \
|
||||
xpcom \
|
||||
|
|
|
@ -56,24 +56,7 @@ nsTextAccessibleWrap(aDomNode, aShell)
|
|||
NS_IMETHODIMP nsHTMLTextAccessible::GetName(nsAString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
if (!mDOMNode) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsIFrame *frame = GetFrame();
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
nsAutoString name;
|
||||
nsresult rv = mDOMNode->GetNodeValue(name);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!frame->GetStyleText()->WhiteSpaceIsSignificant()) {
|
||||
// Replace \r\n\t in markup with space unless in this is preformatted text
|
||||
// where those characters are significant
|
||||
name.ReplaceChar("\r\n\t", ' ');
|
||||
}
|
||||
aName = name;
|
||||
return rv;
|
||||
return AppendTextTo(aName, 0, PR_UINT32_MAX);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLTextAccessible::GetRole(PRUint32 *aRole)
|
||||
|
@ -367,9 +350,14 @@ nsHTMLListBulletAccessible::GetParent(nsIAccessible **aParentAccessible)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLListBulletAccessible::GetContentText(nsAString& aText)
|
||||
nsHTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
aText = mBulletText;
|
||||
PRUint32 maxLength = mBulletText.Length() - aStartOffset;
|
||||
if (aLength > maxLength) {
|
||||
aLength = maxLength;
|
||||
}
|
||||
aText += nsDependentSubstring(mBulletText, aStartOffset, aLength);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ public:
|
|||
NS_IMETHOD GetParent(nsIAccessible **aParentAccessible);
|
||||
|
||||
// nsPIAccessible
|
||||
NS_IMETHOD GetContentText(nsAString& aText);
|
||||
NS_IMETHOD AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength);
|
||||
|
||||
protected:
|
||||
// XXX: Ideally we'd get the bullet text directly from the bullet frame via
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "nsIPlaintextEditor.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "gfxSkipChars.h"
|
||||
|
||||
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
||||
|
||||
|
@ -238,13 +239,24 @@ void nsHyperTextAccessible::CacheChildren()
|
|||
}
|
||||
|
||||
// Substring must be entirely within the same text node
|
||||
nsIntRect nsHyperTextAccessible::GetBoundsForString(nsIFrame *aFrame, PRInt32 aStartOffset, PRInt32 aLength)
|
||||
nsIntRect nsHyperTextAccessible::GetBoundsForString(nsIFrame *aFrame, PRInt32 aStartContentOffset,
|
||||
PRInt32 aEndContentOffset)
|
||||
{
|
||||
nsIntRect screenRect;
|
||||
NS_ENSURE_TRUE(aFrame, screenRect);
|
||||
|
||||
PRUint32 startRenderedOFfset, endRenderedOFfset;
|
||||
nsresult rv = ContentToRenderedOffset(aFrame, aStartContentOffset, &startRenderedOFfset);
|
||||
NS_ENSURE_SUCCESS(rv, screenRect);
|
||||
rv = ContentToRenderedOffset(aFrame, aEndContentOffset, &endRenderedOFfset);
|
||||
NS_ENSURE_SUCCESS(rv, screenRect);
|
||||
|
||||
nsIFrame *frame;
|
||||
PRInt32 startOffsetInFrame;
|
||||
nsresult rv = aFrame->GetChildFrameContainingOffset(aStartOffset, PR_FALSE,
|
||||
&startOffsetInFrame, &frame);
|
||||
PRInt32 startRenderedOFfsetInFrame;
|
||||
// Get the right frame continuation -- not really a child, but a sibling of
|
||||
// the primary frame passed in
|
||||
rv = aFrame->GetChildFrameContainingOffset(startRenderedOFfset, PR_FALSE,
|
||||
&startRenderedOFfsetInFrame, &frame);
|
||||
NS_ENSURE_SUCCESS(rv, screenRect);
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = GetPresShell();
|
||||
|
@ -262,7 +274,7 @@ nsIntRect nsHyperTextAccessible::GetBoundsForString(nsIFrame *aFrame, PRInt32 aS
|
|||
|
||||
nsPresContext *context = shell->GetPresContext();
|
||||
|
||||
while (frame && aLength > 0) {
|
||||
while (frame && startRenderedOFfset < endRenderedOFfset) {
|
||||
// Start with this frame's screen rect, which we will
|
||||
// shrink based on the substring we care about within it.
|
||||
// We will then add that frame to the total screenRect we
|
||||
|
@ -273,26 +285,26 @@ nsIntRect nsHyperTextAccessible::GetBoundsForString(nsIFrame *aFrame, PRInt32 aS
|
|||
PRInt32 startFrameTextOffset, endFrameTextOffset;
|
||||
frame->GetOffsets(startFrameTextOffset, endFrameTextOffset);
|
||||
PRInt32 frameTotalTextLength = endFrameTextOffset - startFrameTextOffset;
|
||||
PRInt32 frameSubStringLength = PR_MIN(frameTotalTextLength - startOffsetInFrame, aLength);
|
||||
PRInt32 seekLength = endRenderedOFfset - startRenderedOFfset;
|
||||
PRInt32 frameSubStringLength = PR_MIN(frameTotalTextLength - startRenderedOFfsetInFrame, seekLength);
|
||||
|
||||
// Add the point where the string starts to the frameScreenRect
|
||||
nsPoint frameTextStartPoint;
|
||||
rv = frame->GetPointFromOffset(context, rc, aStartOffset, &frameTextStartPoint);
|
||||
rv = frame->GetPointFromOffset(context, rc, startRenderedOFfset, &frameTextStartPoint);
|
||||
NS_ENSURE_SUCCESS(rv, nsRect());
|
||||
frameScreenRect.x += context->AppUnitsToDevPixels(frameTextStartPoint.x);
|
||||
|
||||
// Use the point for the end offset to calculate the width
|
||||
nsPoint frameTextEndPoint;
|
||||
rv = frame->GetPointFromOffset(context, rc, aStartOffset + frameSubStringLength, &frameTextEndPoint);
|
||||
rv = frame->GetPointFromOffset(context, rc, startRenderedOFfset + frameSubStringLength, &frameTextEndPoint);
|
||||
NS_ENSURE_SUCCESS(rv, nsRect());
|
||||
frameScreenRect.width = context->AppUnitsToDevPixels(frameTextEndPoint.x - frameTextStartPoint.x);
|
||||
|
||||
screenRect.UnionRect(frameScreenRect, screenRect);
|
||||
|
||||
// Get ready to loop back for next frame continuation
|
||||
aStartOffset += frameSubStringLength;
|
||||
startOffsetInFrame = 0;
|
||||
aLength -= frameSubStringLength;
|
||||
startRenderedOFfset += frameSubStringLength;
|
||||
startRenderedOFfsetInFrame = 0;
|
||||
frame = frame->GetNextContinuation();
|
||||
}
|
||||
|
||||
|
@ -331,6 +343,9 @@ nsIFrame* nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& a
|
|||
nsIntRect unionRect;
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
|
||||
gfxSkipChars skipChars;
|
||||
gfxSkipCharsIterator iter;
|
||||
|
||||
// Loop through children and collect valid offsets, text and bounds
|
||||
// depending on what we need for out parameters
|
||||
while (NextChild(accessible)) {
|
||||
|
@ -340,56 +355,58 @@ nsIFrame* nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& a
|
|||
continue;
|
||||
}
|
||||
if (IsText(accessible)) {
|
||||
nsCOMPtr<nsPIAccessible> pAcc(do_QueryInterface(accessible));
|
||||
nsAutoString newText;
|
||||
pAcc->GetContentText(newText);
|
||||
|
||||
PRInt32 substringEndOffset = newText.Length();
|
||||
// We only need info up to rendered offset -- that is what we're converting to content offset
|
||||
PRInt32 substringEndOffset;
|
||||
nsresult rv = frame->GetRenderedText(nsnull, &skipChars, &iter);
|
||||
PRUint32 ourRenderedStart = iter.GetSkippedOffset();
|
||||
PRInt32 ourContentStart = iter.GetOriginalOffset();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
substringEndOffset = iter.ConvertOriginalToSkipped(skipChars.GetOriginalCharCount() + ourContentStart) -
|
||||
ourRenderedStart;
|
||||
}
|
||||
else {
|
||||
// XXX for non-textframe text like list bullets, should go away after list bullet rewrite
|
||||
substringEndOffset = TextLength(accessible);
|
||||
}
|
||||
if (startOffset < substringEndOffset) {
|
||||
// Our start is within this substring
|
||||
// XXX Can we somehow optimize further by getting the nsTextFragment
|
||||
// and use CopyTo to a PRUnichar buffer to copy it directly to
|
||||
// the string?
|
||||
|
||||
if (startOffset > 0 || endOffset < substringEndOffset) {
|
||||
// XXX the Substring operation is efficient, but does the
|
||||
// reassignment to the original nsAutoString cause a copy?
|
||||
// We don't want the whole string for this accessible
|
||||
// Get out the continuing text frame with this offset
|
||||
PRInt32 outStartLineUnused;
|
||||
frame->GetChildFrameContainingOffset(startOffset, PR_TRUE, &outStartLineUnused, &frame);
|
||||
if (endOffset < substringEndOffset) {
|
||||
// Don't take entire substring: stop before the end
|
||||
substringEndOffset = endOffset;
|
||||
}
|
||||
if (aText) {
|
||||
newText = Substring(newText, startOffset,
|
||||
substringEndOffset - startOffset);
|
||||
}
|
||||
PRInt32 contentOffset = iter.ConvertSkippedToOriginal(startOffset) + ourRenderedStart - ourContentStart;
|
||||
frame->GetChildFrameContainingOffset(contentOffset, PR_TRUE, &outStartLineUnused, &frame);
|
||||
if (aEndFrame) {
|
||||
*aEndFrame = frame; // We ended in the current frame
|
||||
}
|
||||
if (substringEndOffset > endOffset) {
|
||||
// Need to stop before the end of the available text
|
||||
substringEndOffset = endOffset;
|
||||
}
|
||||
aEndOffset = endOffset;
|
||||
}
|
||||
if (aText) {
|
||||
if (!frame->GetStyleText()->WhiteSpaceIsSignificant()) {
|
||||
// Replace \r\n\t in markup with space unless in this is
|
||||
// preformatted text where those characters are significant
|
||||
newText.ReplaceChar("\r\n\t", ' ');
|
||||
}
|
||||
*aText += newText;
|
||||
nsCOMPtr<nsPIAccessible> pAcc(do_QueryInterface(accessible));
|
||||
pAcc->AppendTextTo(*aText, startOffset, substringEndOffset - startOffset);
|
||||
}
|
||||
if (aBoundsRect) {
|
||||
if (aBoundsRect) { // Caller wants the bounds of the text
|
||||
aBoundsRect->UnionRect(*aBoundsRect, GetBoundsForString(frame, startOffset,
|
||||
substringEndOffset - startOffset));
|
||||
substringEndOffset));
|
||||
}
|
||||
if (!startFrame) {
|
||||
startFrame = frame;
|
||||
aStartOffset = startOffset;
|
||||
}
|
||||
// We already started copying in this accessible's string,
|
||||
// for the next accessible we'll start at offset 0
|
||||
startOffset = 0;
|
||||
}
|
||||
else {
|
||||
// We have not found the start position yet, get the new startOffset
|
||||
// that is relative to next accessible
|
||||
startOffset -= substringEndOffset;
|
||||
}
|
||||
// The endOffset needs to be relative to the new startOffset
|
||||
endOffset -= substringEndOffset;
|
||||
}
|
||||
else {
|
||||
|
@ -448,7 +465,9 @@ NS_IMETHODIMP nsHyperTextAccessible::GetCharacterCount(PRInt32 *aCharacterCount)
|
|||
nsCOMPtr<nsIAccessible> accessible;
|
||||
|
||||
while (NextChild(accessible)) {
|
||||
*aCharacterCount += TextLength(accessible);
|
||||
PRInt32 textLength = TextLength(accessible);
|
||||
NS_ENSURE_TRUE(textLength >= 0, nsnull);
|
||||
*aCharacterCount += textLength;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -464,24 +483,28 @@ NS_IMETHODIMP nsHyperTextAccessible::GetCharacterAtOffset(PRInt32 aOffset, PRUni
|
|||
nsAutoString text;
|
||||
nsresult rv = GetText(aOffset, aOffset + 1, text);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (text.IsEmpty()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aCharacter = text.First();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsHyperTextAccessible::DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32* aResult,
|
||||
nsIAccessible **aFinalAccessible)
|
||||
nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset,
|
||||
PRInt32* aHyperTextOffset,
|
||||
nsIAccessible **aFinalAccessible)
|
||||
{
|
||||
// Turn a DOM Node and offset into an offset into this hypertext.
|
||||
// On failure, return null. On success, return the DOM node which contains the offset.
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = 0;
|
||||
NS_ENSURE_ARG_POINTER(aHyperTextOffset);
|
||||
*aHyperTextOffset = 0;
|
||||
NS_ENSURE_ARG_POINTER(aNode);
|
||||
NS_ENSURE_TRUE(aNodeOffset >= 0, NS_ERROR_INVALID_ARG);
|
||||
if (aFinalAccessible) {
|
||||
*aFinalAccessible = nsnull;
|
||||
}
|
||||
|
||||
PRInt32 addTextOffset = 0;
|
||||
PRUint32 addTextOffset = 0;
|
||||
nsCOMPtr<nsIDOMNode> findNode;
|
||||
|
||||
unsigned short nodeType;
|
||||
|
@ -489,7 +512,15 @@ nsresult nsHyperTextAccessible::DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNod
|
|||
if (nodeType == nsIDOMNode::TEXT_NODE) {
|
||||
// For text nodes, aNodeOffset comes in as a character offset
|
||||
// Text offset will be added at the end, if we find the offset in this hypertext
|
||||
addTextOffset = aNodeOffset;
|
||||
// We want the "skipped" offset into the text (rendered text without the extra whitespace)
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
||||
NS_ASSERTION(content, "No nsIContent for dom node");
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
nsIFrame *frame = presShell->GetPrimaryFrameFor(content);
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
nsresult rv = ContentToRenderedOffset(frame, aNodeOffset, &addTextOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Get the child node and
|
||||
findNode = aNode;
|
||||
}
|
||||
|
@ -505,7 +536,7 @@ nsresult nsHyperTextAccessible::DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNod
|
|||
|
||||
findNode = do_QueryInterface(parentContent->GetChildAt(aNodeOffset));
|
||||
if (!findNode && !aNodeOffset) {
|
||||
NS_ASSERTION(!SameCOMIdentity(parentContent, mDOMNode), "Cannot find child for DOMPointToOffset search");
|
||||
NS_ASSERTION(!SameCOMIdentity(parentContent, mDOMNode), "Cannot find child for DOMPointToHypertextOffset search");
|
||||
findNode = do_QueryInterface(parentContent); // Case #2: there are no children
|
||||
}
|
||||
}
|
||||
|
@ -543,12 +574,14 @@ nsresult nsHyperTextAccessible::DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNod
|
|||
// came after the last accessible child's node
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
while (NextChild(accessible) && accessible != childAccessible) {
|
||||
*aResult += TextLength(accessible);
|
||||
PRInt32 textLength = TextLength(accessible);
|
||||
NS_ENSURE_TRUE(textLength >= 0, nsnull);
|
||||
*aHyperTextOffset += textLength;
|
||||
}
|
||||
if (accessible) {
|
||||
*aResult += addTextOffset;
|
||||
*aHyperTextOffset += addTextOffset;
|
||||
NS_ASSERTION(accessible == childAccessible, "These should be equal whenever we exit loop and accessible != nsnull");
|
||||
if (aFinalAccessible && (NextChild(accessible) || addTextOffset < TextLength(childAccessible))) {
|
||||
if (aFinalAccessible && (NextChild(accessible) || static_cast<PRInt32>(addTextOffset) < TextLength(childAccessible))) {
|
||||
// If not at end of last text node, we will return the accessible we were in
|
||||
NS_ADDREF(*aFinalAccessible = childAccessible);
|
||||
}
|
||||
|
@ -571,10 +604,15 @@ PRInt32 nsHyperTextAccessible::GetRelativeOffset(nsIPresShell *aPresShell, nsIFr
|
|||
|
||||
// Ask layout for the new node and offset, after moving the appropriate amount
|
||||
nsPeekOffsetStruct pos;
|
||||
pos.SetData(aAmount, aDirection, aFromOffset, 0, kIsJumpLinesOk,
|
||||
kIsScrollViewAStop, kIsKeyboardSelect, kIsVisualBidi,
|
||||
|
||||
PRInt32 contentOffset;
|
||||
nsresult rv = RenderedToContentOffset(aFromFrame, aFromOffset, &contentOffset);
|
||||
NS_ENSURE_SUCCESS(rv, -1);
|
||||
|
||||
pos.SetData(aAmount, aDirection, contentOffset,
|
||||
0, kIsJumpLinesOk, kIsScrollViewAStop, kIsKeyboardSelect, kIsVisualBidi,
|
||||
wordMovementType);
|
||||
nsresult rv = aFromFrame->PeekOffset(&pos);
|
||||
rv = aFromFrame->PeekOffset(&pos);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (aDirection == eDirPrevious) {
|
||||
// Use passed-in frame as starting point in failure case for now,
|
||||
|
@ -586,7 +624,7 @@ PRInt32 nsHyperTextAccessible::GetRelativeOffset(nsIPresShell *aPresShell, nsIFr
|
|||
aFromFrame->GetOffsets(pos.mContentOffset, endOffsetUnused);
|
||||
}
|
||||
else {
|
||||
return rv;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,8 +634,8 @@ PRInt32 nsHyperTextAccessible::GetRelativeOffset(nsIPresShell *aPresShell, nsIFr
|
|||
NS_ENSURE_TRUE(resultNode, -1);
|
||||
|
||||
nsCOMPtr<nsIAccessible> finalAccessible;
|
||||
rv = DOMPointToOffset(resultNode, pos.mContentOffset, &hyperTextOffset, getter_AddRefs(finalAccessible));
|
||||
// If finalAccessible == nsnull, then DOMPointToOffset() searched through the hypertext
|
||||
rv = DOMPointToHypertextOffset(resultNode, pos.mContentOffset, &hyperTextOffset, getter_AddRefs(finalAccessible));
|
||||
// If finalAccessible == nsnull, then DOMPointToHypertextOffset() searched through the hypertext
|
||||
// children without finding the node/offset position
|
||||
NS_ENSURE_SUCCESS(rv, -1);
|
||||
|
||||
|
@ -713,7 +751,11 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe
|
|||
// If not text, then it's represented by an embedded object char
|
||||
// (length of 1)
|
||||
// XXX did this mean to check for eTEXT?
|
||||
// XXX This is completely wrong, needs to be reimplemented
|
||||
PRInt32 textLength = textContent ? textContent->TextLength() : 1;
|
||||
if (textLength < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aStartOffset = aOffset - startOffset;
|
||||
*aEndOffset = *aStartOffset + textLength;
|
||||
startOffset = *aStartOffset;
|
||||
|
@ -812,6 +854,7 @@ NS_IMETHODIMP nsHyperTextAccessible::GetAttributeRange(PRInt32 aOffset, PRInt32
|
|||
|
||||
while (NextChild(accessible)) {
|
||||
PRInt32 length = TextLength(accessible);
|
||||
NS_ENSURE_TRUE(length >= 0, NS_ERROR_FAILURE);
|
||||
if (*aRangeStartOffset + length > aOffset) {
|
||||
*aRangeEndOffset = *aRangeStartOffset + length;
|
||||
NS_ADDREF(*aAccessibleWithAttrs = accessible);
|
||||
|
@ -993,14 +1036,19 @@ nsHyperTextAccessible::GetOffsetAtPoint(PRInt32 aX, PRInt32 aY,
|
|||
if (contentOffsets.IsNull() || contentOffsets.content != content) {
|
||||
return NS_OK; // Not found, will return -1
|
||||
}
|
||||
offset += contentOffsets.offset;
|
||||
PRUint32 addToOffset;
|
||||
nsresult rv = ContentToRenderedOffset(frame, contentOffsets.offset, &addToOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
offset += addToOffset;
|
||||
}
|
||||
*aOffset = offset;
|
||||
return NS_OK;
|
||||
}
|
||||
frame = frame->GetNextContinuation();
|
||||
}
|
||||
offset += TextLength(accessible);
|
||||
PRInt32 textLength = TextLength(accessible);
|
||||
NS_ENSURE_TRUE(textLength >= 0, NS_ERROR_FAILURE);
|
||||
offset += textLength;
|
||||
}
|
||||
|
||||
return NS_OK; // Not found, will return -1
|
||||
|
@ -1059,7 +1107,9 @@ NS_IMETHODIMP nsHyperTextAccessible::GetLinkIndex(PRInt32 aCharIndex, PRInt32 *a
|
|||
PRUint32 role = Role(accessible);
|
||||
if (role == nsIAccessibleRole::ROLE_TEXT_LEAF ||
|
||||
role == nsIAccessibleRole::ROLE_STATICTEXT) {
|
||||
characterCount += TextLength(accessible);
|
||||
PRInt32 textLength = TextLength(accessible);
|
||||
NS_ENSURE_TRUE(textLength >= 0, NS_ERROR_FAILURE);
|
||||
characterCount += textLength;
|
||||
}
|
||||
else {
|
||||
if (characterCount ++ == aCharIndex) {
|
||||
|
@ -1208,7 +1258,7 @@ NS_IMETHODIMP nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
|
|||
PRInt32 caretOffset;
|
||||
domSel->GetFocusOffset(&caretOffset);
|
||||
|
||||
return DOMPointToOffset(caretNode, caretOffset, aCaretOffset);
|
||||
return DOMPointToHypertextOffset(caretNode, caretOffset, aCaretOffset);
|
||||
}
|
||||
|
||||
nsresult nsHyperTextAccessible::GetSelections(nsISelectionController **aSelCon, nsISelection **aDomSel)
|
||||
|
@ -1301,7 +1351,7 @@ NS_IMETHODIMP nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, P
|
|||
range->GetStartContainer(getter_AddRefs(startNode));
|
||||
PRInt32 startOffset;
|
||||
range->GetStartOffset(&startOffset);
|
||||
rv = DOMPointToOffset(startNode, startOffset, aStartOffset);
|
||||
rv = DOMPointToHypertextOffset(startNode, startOffset, aStartOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
|
@ -1313,7 +1363,7 @@ NS_IMETHODIMP nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, P
|
|||
*aEndOffset = *aStartOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
return DOMPointToOffset(endNode, endOffset, aEndOffset);
|
||||
return DOMPointToHypertextOffset(endNode, endOffset, aEndOffset);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1414,3 +1464,39 @@ NS_IMETHODIMP nsHyperTextAccessible::RemoveSelection(PRInt32 aSelectionNum)
|
|||
return domSel->RemoveRange(range);
|
||||
}
|
||||
|
||||
nsresult nsHyperTextAccessible::ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
|
||||
PRUint32 *aRenderedOffset)
|
||||
{
|
||||
gfxSkipChars skipChars;
|
||||
gfxSkipCharsIterator iter;
|
||||
// Only get info up to original ofset, we know that will be larger than skipped offset
|
||||
nsresult rv = aFrame->GetRenderedText(nsnull, &skipChars, &iter, 0, aContentOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 ourRenderedStart = iter.GetSkippedOffset();
|
||||
PRInt32 ourContentStart = iter.GetOriginalOffset();
|
||||
|
||||
*aRenderedOffset = iter.ConvertOriginalToSkipped(aContentOffset + ourContentStart) -
|
||||
ourRenderedStart;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsHyperTextAccessible::RenderedToContentOffset(nsIFrame *aFrame, PRUint32 aRenderedOffset,
|
||||
PRInt32 *aContentOffset)
|
||||
{
|
||||
gfxSkipChars skipChars;
|
||||
gfxSkipCharsIterator iter;
|
||||
// We only need info up to skipped offset -- that is what we're converting to original offset
|
||||
nsresult rv = aFrame->GetRenderedText(nsnull, &skipChars, &iter, 0, aRenderedOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 ourRenderedStart = iter.GetSkippedOffset();
|
||||
PRInt32 ourContentStart = iter.GetOriginalOffset();
|
||||
|
||||
*aContentOffset = iter.ConvertSkippedToOriginal(aRenderedOffset + ourRenderedStart) - ourContentStart;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,6 +86,14 @@ public:
|
|||
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
|
||||
void CacheChildren();
|
||||
|
||||
// Convert content offset to rendered text offset
|
||||
static nsresult ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
|
||||
PRUint32 *aRenderedOffset);
|
||||
|
||||
// Convert rendered text offset to content offset
|
||||
static nsresult RenderedToContentOffset(nsIFrame *aFrame, PRUint32 aRenderedOffset,
|
||||
PRInt32 *aContentOffset);
|
||||
|
||||
/**
|
||||
* Turn a DOM Node and offset into a character offset into this hypertext.
|
||||
* Will look for closest match when the DOM node does not have an accessible
|
||||
|
@ -101,9 +109,9 @@ public:
|
|||
* the current nsHyperTextAccessible,
|
||||
* otherwise it is set to nsnull.
|
||||
*/
|
||||
nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset,
|
||||
PRInt32 *aResultOffset,
|
||||
nsIAccessible **aFinalAccessible = nsnull);
|
||||
nsresult DOMPointToHypertextOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset,
|
||||
PRInt32 *aHypertextOffset,
|
||||
nsIAccessible **aFinalAccessible = nsnull);
|
||||
|
||||
protected:
|
||||
PRBool IsHyperText();
|
||||
|
@ -138,9 +146,9 @@ protected:
|
|||
* Given a start offset and end offset, get substring information. Different info is returned depending
|
||||
* on what optional paramters are provided.
|
||||
* @param aStartOffset, the start offset into the hyper text. This is also an out parameter used to return
|
||||
* the offset into the start frame's text content (start frame is the @return)
|
||||
* @param aEndOffset, the endoffset into the hyper text. This is also an out parameter used to return
|
||||
* the offset into the end frame's text content
|
||||
* the offset into the start frame's rendered text content (start frame is the @return)
|
||||
* @param aEndHyperOffset, the endoffset into the hyper text. This is also an out parameter used to return
|
||||
* the offset into the end frame's rendered text content
|
||||
* @param aText (optional), return the substring's text
|
||||
* @param aEndFrame (optional), return the end frame for this substring
|
||||
* @param aBoundsRect (optional), return the bounds rectangle for this substring
|
||||
|
@ -149,7 +157,7 @@ protected:
|
|||
nsIFrame* GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset, nsAString *aText = nsnull,
|
||||
nsIFrame **aEndFrame = nsnull, nsIntRect *aBoundsRect = nsnull);
|
||||
|
||||
nsIntRect GetBoundsForString(nsIFrame *aFrame, PRInt32 aStartOffset, PRInt32 aLength);
|
||||
nsIntRect GetBoundsForString(nsIFrame *aFrame, PRInt32 aStartContentOffset, PRInt32 aEndContentOffset);
|
||||
|
||||
// Editor helpers, subclasses of nsHyperTextAccessible may have editor
|
||||
virtual void SetEditor(nsIEditor *aEditor) { return; }
|
||||
|
|
|
@ -90,6 +90,8 @@ class nsIAccessible;
|
|||
class nsDisplayListBuilder;
|
||||
class nsDisplayListSet;
|
||||
class nsDisplayList;
|
||||
class gfxSkipChars;
|
||||
class gfxSkipCharsIterator;
|
||||
|
||||
struct nsPeekOffsetStruct;
|
||||
struct nsPoint;
|
||||
|
@ -1398,6 +1400,28 @@ public:
|
|||
nscoord& aDeltaWidth,
|
||||
PRBool& aLastCharIsJustifiable) = 0;
|
||||
|
||||
/**
|
||||
* Append the rendered text to the passed-in string.
|
||||
* The appended text will often not contain all the whitespace from source,
|
||||
* depending on whether the CSS rule "white-space: pre" is active for this frame.
|
||||
* if aStartOffset + aLength goes past end, or if aLength is not specified
|
||||
* then use the text up to the string's end.
|
||||
* Call this on the primary frame for a text node.
|
||||
* @param aAppendToString String to append text to, or null if text should not be returned
|
||||
* @param aSkipChars if aSkipIter is non-null, this must also be non-null.
|
||||
* This gets used as backing data for the iterator so it should outlive the iterator.
|
||||
* @param aSkipIter Where to fill in the gfxSkipCharsIterator info, or null if not needed by caller
|
||||
* @param aStartOffset Skipped (rendered text) start offset
|
||||
* @param aSkippedMaxLength Maximum number of characters to return
|
||||
* The iterator can be used to map content offsets to offsets in the returned string, or vice versa.
|
||||
*/
|
||||
virtual nsresult GetRenderedText(nsAString* aAppendToString = nsnull,
|
||||
gfxSkipChars* aSkipChars = nsnull,
|
||||
gfxSkipCharsIterator* aSkipIter = nsnull,
|
||||
PRUint32 aSkippedStartOffset = 0,
|
||||
PRUint32 aSkippedMaxLength = PR_UINT32_MAX)
|
||||
{ return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/**
|
||||
* Accessor functions to get/set the associated view object
|
||||
*
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#include "nsFrameManager.h"
|
||||
#include "nsTextFrameTextRunCache.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsICaseConversion.h"
|
||||
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
@ -449,6 +450,11 @@ public:
|
|||
nsIRenderingContext& aRC,
|
||||
nscoord& aDeltaWidth,
|
||||
PRBool& aLastCharIsJustifiable);
|
||||
virtual nsresult GetRenderedText(nsAString* aString = nsnull,
|
||||
gfxSkipChars* aSkipChars = nsnull,
|
||||
gfxSkipCharsIterator* aSkipIter = nsnull,
|
||||
PRUint32 aSkippedStartOffset = 0,
|
||||
PRUint32 aSkippedMaxLength = PR_UINT32_MAX);
|
||||
|
||||
void AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlineMinWidthData *aData);
|
||||
|
@ -539,6 +545,7 @@ public:
|
|||
struct TrimmedOffsets {
|
||||
PRInt32 mStart;
|
||||
PRInt32 mLength;
|
||||
PRInt32 GetEnd() { return mStart + mLength; }
|
||||
};
|
||||
TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag,
|
||||
PRBool aTrimAfter);
|
||||
|
@ -2048,7 +2055,7 @@ nsTextFrame::GetTrimmedOffsets(const nsTextFragment* aFrag,
|
|||
if (aTrimAfter && (GetStateBits() & TEXT_END_OF_LINE) &&
|
||||
textStyle->WhiteSpaceCanWrap()) {
|
||||
PRInt32 whitespaceCount =
|
||||
GetTrimmableWhitespaceCount(aFrag, offsets.mStart + offsets.mLength - 1,
|
||||
GetTrimmableWhitespaceCount(aFrag, offsets.GetEnd() - 1,
|
||||
offsets.mLength, -1);
|
||||
offsets.mLength -= whitespaceCount;
|
||||
}
|
||||
|
@ -3260,6 +3267,13 @@ public:
|
|||
virtual void AddInlinePrefWidth(nsIRenderingContext *aRenderingContext,
|
||||
InlinePrefWidthData *aData);
|
||||
|
||||
virtual nsresult GetRenderedText(nsAString* aString = nsnull,
|
||||
gfxSkipChars* aSkipChars = nsnull,
|
||||
gfxSkipCharsIterator* aSkipIter = nsnull,
|
||||
PRUint32 aSkippedStartOffset = 0,
|
||||
PRUint32 aSkippedMaxLength = PR_UINT32_MAX)
|
||||
{ return NS_ERROR_NOT_IMPLEMENTED; } // Call on a primary text frame only
|
||||
|
||||
protected:
|
||||
nsContinuingTextFrame(nsStyleContext* aContext) : nsTextFrame(aContext) {}
|
||||
nsIFrame* mPrevContinuation;
|
||||
|
@ -4589,7 +4603,7 @@ nsTextFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset)
|
|||
|
||||
TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), PR_TRUE);
|
||||
// Check whether there are nonskipped characters in the trimmmed range
|
||||
return iter.ConvertOriginalToSkipped(trimmed.mStart + trimmed.mLength) >
|
||||
return iter.ConvertOriginalToSkipped(trimmed.GetEnd()) >
|
||||
iter.ConvertOriginalToSkipped(trimmed.mStart);
|
||||
}
|
||||
|
||||
|
@ -4644,7 +4658,7 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
|
|||
|
||||
if (!aForward) {
|
||||
PRInt32 i;
|
||||
for (i = PR_MIN(trimmed.mStart + trimmed.mLength, startOffset) - 1;
|
||||
for (i = PR_MIN(trimmed.GetEnd(), startOffset) - 1;
|
||||
i >= trimmed.mStart; --i) {
|
||||
iter.SetOriginalOffset(i);
|
||||
if (!iter.IsOriginalCharSkipped() &&
|
||||
|
@ -4656,12 +4670,12 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
|
|||
*aOffset = 0;
|
||||
} else {
|
||||
PRInt32 i;
|
||||
for (i = startOffset + 1; i <= trimmed.mStart + trimmed.mLength; ++i) {
|
||||
for (i = startOffset + 1; i <= trimmed.GetEnd(); ++i) {
|
||||
iter.SetOriginalOffset(i);
|
||||
// XXX we can't necessarily stop at the end of this frame,
|
||||
// but we really have no choice right now. We need to do a deeper
|
||||
// fix/restructuring of PeekOffsetCharacter
|
||||
if (i == trimmed.mStart + trimmed.mLength ||
|
||||
if (i == trimmed.GetEnd() ||
|
||||
(!iter.IsOriginalCharSkipped() &&
|
||||
mTextRun->IsClusterStart(iter.GetSkippedOffset()))) {
|
||||
*aOffset = i - mContentOffset;
|
||||
|
@ -4717,7 +4731,7 @@ ClusterIterator::NextCluster()
|
|||
|
||||
while (PR_TRUE) {
|
||||
if (mDirection > 0) {
|
||||
if (mIterator.GetOriginalOffset() >= mTrimmed.mStart + mTrimmed.mLength)
|
||||
if (mIterator.GetOriginalOffset() >= mTrimmed.GetEnd())
|
||||
return PR_FALSE;
|
||||
if (mIterator.IsOriginalCharSkipped() ||
|
||||
mIterator.GetOriginalOffset() < mTrimmed.mStart ||
|
||||
|
@ -4732,7 +4746,7 @@ ClusterIterator::NextCluster()
|
|||
return PR_FALSE;
|
||||
mIterator.AdvanceOriginal(-1);
|
||||
if (mIterator.IsOriginalCharSkipped() ||
|
||||
mIterator.GetOriginalOffset() >= mTrimmed.mStart + mTrimmed.mLength ||
|
||||
mIterator.GetOriginalOffset() >= mTrimmed.GetEnd() ||
|
||||
!textRun->IsClusterStart(mIterator.GetSkippedOffset()))
|
||||
continue;
|
||||
mCharIndex = mIterator.GetOriginalOffset();
|
||||
|
@ -5581,13 +5595,13 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
|
|||
const nsTextFragment* frag = mContent->GetText();
|
||||
TrimmedOffsets trimmed = GetTrimmedOffsets(frag, PR_TRUE);
|
||||
gfxSkipCharsIterator iter = start;
|
||||
PRUint32 trimmedEnd = iter.ConvertOriginalToSkipped(trimmed.mStart + trimmed.mLength);
|
||||
PRUint32 trimmedEnd = iter.ConvertOriginalToSkipped(trimmed.GetEnd());
|
||||
const nsStyleText* textStyle = GetStyleText();
|
||||
gfxFloat delta = 0;
|
||||
|
||||
if (GetStateBits() & TEXT_TRIMMED_TRAILING_WHITESPACE) {
|
||||
aLastCharIsJustifiable = PR_TRUE;
|
||||
} else if (trimmed.mStart + trimmed.mLength < mContentOffset + mContentLength) {
|
||||
} else if (trimmed.GetEnd() < GetContentEnd()) {
|
||||
gfxSkipCharsIterator end = iter;
|
||||
PRUint32 endOffset = end.ConvertOriginalToSkipped(mContentOffset + mContentLength);
|
||||
if (trimmedEnd < endOffset) {
|
||||
|
@ -5613,7 +5627,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
|
|||
provider.FindEndOfJustificationRange(&justificationEnd);
|
||||
|
||||
PRInt32 i;
|
||||
for (i = justificationEnd.GetOriginalOffset(); i < trimmed.mStart + trimmed.mLength; ++i) {
|
||||
for (i = justificationEnd.GetOriginalOffset(); i < trimmed.GetEnd(); ++i) {
|
||||
if (IsJustifiableCharacter(frag, i, isCJK)) {
|
||||
aLastCharIsJustifiable = PR_TRUE;
|
||||
}
|
||||
|
@ -5653,6 +5667,98 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRUnichar TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
|
||||
PRUint32 aSkippedOffset, PRUnichar aChar)
|
||||
{
|
||||
if (aChar == '\n' || aChar == '\r') {
|
||||
return aStyle->WhiteSpaceIsSignificant() ? aChar : ' ';
|
||||
}
|
||||
switch (aStyle->mTextTransform) {
|
||||
case NS_STYLE_TEXT_TRANSFORM_LOWERCASE:
|
||||
nsContentUtils::GetCaseConv()->ToLower(aChar, &aChar);
|
||||
break;
|
||||
case NS_STYLE_TEXT_TRANSFORM_UPPERCASE:
|
||||
nsContentUtils::GetCaseConv()->ToUpper(aChar, &aChar);
|
||||
break;
|
||||
case NS_STYLE_TEXT_TRANSFORM_CAPITALIZE:
|
||||
if (aTextRun->CanBreakLineBefore(aSkippedOffset)) {
|
||||
nsContentUtils::GetCaseConv()->ToTitle(aChar, &aChar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return aChar;
|
||||
}
|
||||
|
||||
nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString,
|
||||
gfxSkipChars* aSkipChars,
|
||||
gfxSkipCharsIterator* aSkipIter,
|
||||
PRUint32 aSkippedStartOffset,
|
||||
PRUint32 aSkippedMaxLength)
|
||||
{
|
||||
// The handling of aSkippedStartOffset and aSkippedMaxLength could be more efficient...
|
||||
gfxSkipCharsBuilder skipCharsBuilder;
|
||||
nsTextFrame* textFrame;
|
||||
const nsTextFragment* textFrag = mContent->GetText();
|
||||
PRInt32 keptCharsLength = 0;
|
||||
PRInt32 validCharsLength = 0;
|
||||
|
||||
// Build skipChars and copy text, for each text frame in this continuation block
|
||||
for (textFrame = this; textFrame;
|
||||
textFrame = static_cast<nsTextFrame*>(textFrame->GetNextContinuation())) {
|
||||
// For each text frame continuation in this block ...
|
||||
|
||||
// Ensure the text run and grab the gfxSkipCharsIterator for it
|
||||
gfxSkipCharsIterator iter = textFrame->EnsureTextRun();
|
||||
if (!textFrame->mTextRun)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Skip to the start of the text run, past ignored chars at start of line
|
||||
// XXX In the future we may decide to trim extra spaces before a hard line
|
||||
// break, in which case we need to accurately detect those sitations and
|
||||
// call GetTrimmedOffsets() with PR_TRUE to trim whitespace at the line's end
|
||||
TrimmedOffsets trimmedContentOffsets = textFrame->GetTrimmedOffsets(textFrag, PR_FALSE);
|
||||
PRInt32 startOfLineSkipChars = trimmedContentOffsets.mStart - textFrame->mContentOffset;
|
||||
if (startOfLineSkipChars > 0) {
|
||||
skipCharsBuilder.SkipChars(startOfLineSkipChars);
|
||||
iter.SetOriginalOffset(trimmedContentOffsets.mStart);
|
||||
}
|
||||
|
||||
// Keep and copy the appropriate chars withing the caller's requested range
|
||||
const nsStyleText* textStyle = textFrame->GetStyleText();
|
||||
while (iter.GetOriginalOffset() < trimmedContentOffsets.GetEnd() &&
|
||||
keptCharsLength < aSkippedMaxLength) {
|
||||
// For each original char from content text
|
||||
if (iter.IsOriginalCharSkipped() || ++ validCharsLength <= aSkippedStartOffset) {
|
||||
skipCharsBuilder.SkipChar();
|
||||
} else {
|
||||
++ keptCharsLength;
|
||||
skipCharsBuilder.KeepChar();
|
||||
if (aAppendToString) {
|
||||
aAppendToString->Append(
|
||||
TransformChar(textStyle, textFrame->mTextRun, iter.GetSkippedOffset(),
|
||||
textFrag->CharAt(iter.GetOriginalOffset())));
|
||||
}
|
||||
}
|
||||
iter.AdvanceOriginal(1);
|
||||
}
|
||||
if (keptCharsLength >= aSkippedMaxLength) {
|
||||
break; // Already past the end, don't build string or gfxSkipCharsIter anymore
|
||||
}
|
||||
}
|
||||
|
||||
if (aSkipChars) {
|
||||
aSkipChars->TakeFrom(&skipCharsBuilder); // Copy skipChars into aSkipChars
|
||||
if (aSkipIter) {
|
||||
// Caller must provide both pointers in order to retrieve a gfxSkipCharsIterator,
|
||||
// because the gfxSkipCharsIterator holds a weak pointer to the gfxSkipCars.
|
||||
*aSkipIter = gfxSkipCharsIterator(*aSkipChars, GetContentLength());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Translate the mapped content into a string that's printable
|
||||
void
|
||||
|
|
Загрузка…
Ссылка в новой задаче