Bug 475522 - walk subtree once for all text attributes, r=marcoz, davidb, sr=neil

--HG--
rename : accessible/src/base/nsTextUtils.cpp => accessible/src/base/nsTextAttrs.cpp
rename : accessible/src/base/nsTextUtils.h => accessible/src/base/nsTextAttrs.h
This commit is contained in:
Alexander Surkov 2009-01-12 21:34:52 +08:00
Родитель 8b18359400
Коммит 0dcbd2432d
10 изменённых файлов: 1246 добавлений и 960 удалений

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

@ -93,7 +93,7 @@ CPPSRCS = \
nsApplicationAccessible.cpp \
nsCaretAccessible.cpp \
nsTextAccessible.cpp \
nsTextUtils.cpp \
nsTextAttrs.cpp \
$(NULL)
EXPORTS = \

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

@ -193,10 +193,17 @@ ACCESSIBILITY_ATOM(textAlign, "text-align")
ACCESSIBILITY_ATOM(textIndent, "text-indent")
// Alphabetical list of text attributes (AT API)
ACCESSIBILITY_ATOM(color, "color")
ACCESSIBILITY_ATOM(backgroundColor, "background-color")
ACCESSIBILITY_ATOM(fontFamily, "font-family")
ACCESSIBILITY_ATOM(fontStyle, "font-style")
ACCESSIBILITY_ATOM(fontWeight, "font-weight")
ACCESSIBILITY_ATOM(fontSize, "font-size")
ACCESSIBILITY_ATOM(invalid, "invalid")
ACCESSIBILITY_ATOM(language, "language")
ACCESSIBILITY_ATOM(textLineThroughStyle, "text-line-through-style")
ACCESSIBILITY_ATOM(textUnderlineStyle, "text-underline-style")
ACCESSIBILITY_ATOM(textPosition, "text-position")
// ARIA (DHTML accessibility) attributes
// Also add to nsARIAMap.cpp and nsARIAMap.h

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

@ -0,0 +1,605 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsTextAttrs.h"
#include "nsAccessNode.h"
#include "nsHyperTextAccessibleWrap.h"
////////////////////////////////////////////////////////////////////////////////
// Constants and structures
/**
* Item of the gCSSTextAttrsMap map.
*/
struct nsCSSTextAttrMapItem
{
const char* mCSSName;
const char* mCSSValue;
nsIAtom** mAttrName;
const char* mAttrValue;
};
/**
* The map of CSS properties to text attributes.
*/
const char* const kAnyValue = nsnull;
const char* const kCopyValue = nsnull;
static nsCSSTextAttrMapItem gCSSTextAttrsMap[] =
{
// CSS name CSS value Attribute name Attribute value
{ "color", kAnyValue, &nsAccessibilityAtoms::color, kCopyValue },
{ "font-family", kAnyValue, &nsAccessibilityAtoms::fontFamily, kCopyValue },
{ "font-style", kAnyValue, &nsAccessibilityAtoms::fontStyle, kCopyValue },
{ "font-weight", kAnyValue, &nsAccessibilityAtoms::fontWeight, kCopyValue },
{ "text-decoration", "line-through", &nsAccessibilityAtoms::textLineThroughStyle, "solid" },
{ "text-decoration", "underline", &nsAccessibilityAtoms::textUnderlineStyle, "solid" },
{ "vertical-align", kAnyValue, &nsAccessibilityAtoms::textPosition, kCopyValue }
};
////////////////////////////////////////////////////////////////////////////////
// nsTextAttrs
nsTextAttrsMgr::nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
nsIDOMNode *aHyperTextNode,
PRBool aIncludeDefAttrs,
nsIDOMNode *aOffsetNode) :
mHyperTextAcc(aHyperTextAcc), mHyperTextNode(aHyperTextNode),
mIncludeDefAttrs(aIncludeDefAttrs), mOffsetNode(aOffsetNode)
{
}
nsresult
nsTextAttrsMgr::GetAttributes(nsIPersistentProperties *aAttributes,
PRInt32 *aStartHTOffset,
PRInt32 *aEndHTOffset)
{
// 1. Hyper text accessible and its DOM node must be specified always.
// 2. Offset DOM node and result hyper text offsets must be specifed in
// the case of text attributes.
// 3. Offset DOM node and result hyper text offsets must not be specifed but
// include default text attributes flag and attributes list must be specified
// in the case of default text attributes.
NS_PRECONDITION(mHyperTextAcc && mHyperTextNode &&
((mOffsetNode && aStartHTOffset && aEndHTOffset) ||
(!mOffsetNode && !aStartHTOffset && !aEndHTOffset &&
mIncludeDefAttrs && aAttributes)),
"Wrong usage of nsTextAttrsMgr!");
nsCOMPtr<nsIDOMElement> hyperTextElm =
nsCoreUtils::GetDOMElementFor(mHyperTextNode);
nsCOMPtr<nsIDOMElement> offsetElm;
if (mOffsetNode)
offsetElm = nsCoreUtils::GetDOMElementFor(mOffsetNode);
nsIFrame *rootFrame = nsCoreUtils::GetFrameFor(hyperTextElm);
nsIFrame *frame = nsnull;
if (offsetElm)
frame = nsCoreUtils::GetFrameFor(offsetElm);
nsTPtrArray<nsITextAttr> textAttrArray(10);
// "language" text attribute
nsLangTextAttr langTextAttr(mHyperTextAcc, mHyperTextNode, mOffsetNode);
textAttrArray.AppendElement(&langTextAttr);
// "color" text attribute
nsCSSTextAttr colorTextAttr(0, hyperTextElm, offsetElm);
textAttrArray.AppendElement(&colorTextAttr);
// "font-family" text attribute
nsCSSTextAttr fontFamilyTextAttr(1, hyperTextElm, offsetElm);
textAttrArray.AppendElement(&fontFamilyTextAttr);
// "font-style" text attribute
nsCSSTextAttr fontStyleTextAttr(2, hyperTextElm, offsetElm);
textAttrArray.AppendElement(&fontStyleTextAttr);
// "font-weight" text attribute
nsCSSTextAttr fontWeightTextAttr(3, hyperTextElm, offsetElm);
textAttrArray.AppendElement(&fontWeightTextAttr);
// "text-line-through-style" text attribute
nsCSSTextAttr lineThroughTextAttr(4, hyperTextElm, offsetElm);
textAttrArray.AppendElement(&lineThroughTextAttr);
// "text-underline-style" text attribute
nsCSSTextAttr underlineTextAttr(5, hyperTextElm, offsetElm);
textAttrArray.AppendElement(&underlineTextAttr);
// "text-position" text attribute
nsCSSTextAttr posTextAttr(6, hyperTextElm, offsetElm);
textAttrArray.AppendElement(&posTextAttr);
// "background-color" text attribute
nsBGColorTextAttr bgColorTextAttr(rootFrame, frame);
textAttrArray.AppendElement(&bgColorTextAttr);
// "font-size" text attribute
nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
textAttrArray.AppendElement(&fontSizeTextAttr);
// Expose text attributes if applicable.
if (aAttributes) {
PRUint32 len = textAttrArray.Length();
for (PRUint32 idx = 0; idx < len; idx++) {
nsITextAttr *textAttr = textAttrArray[idx];
nsAutoString value;
if (textAttr->GetValue(value, mIncludeDefAttrs))
nsAccUtils::SetAccAttr(aAttributes, textAttr->GetName(), value);
}
}
nsresult rv = NS_OK;
// Expose text attributes range where they are applied if applicable.
if (mOffsetNode)
rv = GetRange(textAttrArray, aStartHTOffset, aEndHTOffset);
textAttrArray.Clear();
return rv;
}
nsresult
nsTextAttrsMgr::GetRange(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset)
{
nsCOMPtr<nsIDOMElement> rootElm =
nsCoreUtils::GetDOMElementFor(mHyperTextNode);
NS_ENSURE_STATE(rootElm);
nsCOMPtr<nsIDOMNode> tmpNode(mOffsetNode);
nsCOMPtr<nsIDOMNode> currNode(mOffsetNode);
PRUint32 len = aTextAttrArray.Length();
// Navigate backwards and forwards from current node to the root node to
// calculate range bounds for the text attribute. Navigation sequence is the
// following:
// 1. Navigate through the siblings.
// 2. If the traversed sibling has children then navigate from its leaf child
// to it through whole tree of the traversed sibling.
// 3. Get the parent and cycle algorithm until the root node.
// Navigate backwards (find the start offset).
while (currNode && currNode != rootElm) {
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
NS_ENSURE_STATE(currElm);
if (currNode != mOffsetNode) {
PRBool stop = PR_FALSE;
for (PRUint32 idx = 0; idx < len; idx++) {
nsITextAttr *textAttr = aTextAttrArray[idx];
if (!textAttr->Equal(currElm)) {
PRInt32 startHTOffset = 0;
nsCOMPtr<nsIAccessible> startAcc;
nsresult rv = mHyperTextAcc->
DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
getter_AddRefs(startAcc));
NS_ENSURE_SUCCESS(rv, rv);
if (!startAcc)
startHTOffset = 0;
if (startHTOffset > *aStartHTOffset)
*aStartHTOffset = startHTOffset;
stop = PR_TRUE;
break;
}
}
if (stop)
break;
}
currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
if (tmpNode) {
// Navigate through the subtree of traversed children to calculate
// left bound of the range.
FindStartOffsetInSubtree(aTextAttrArray, tmpNode, currNode,
aStartHTOffset);
}
currNode->GetParentNode(getter_AddRefs(tmpNode));
currNode.swap(tmpNode);
}
// Navigate forwards (find the end offset).
PRBool moveIntoSubtree = PR_TRUE;
currNode = mOffsetNode;
while (currNode && currNode != rootElm) {
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
NS_ENSURE_STATE(currElm);
// Stop new end offset searching if the given text attribute changes its
// value.
PRBool stop = PR_FALSE;
for (PRUint32 idx = 0; idx < len; idx++) {
nsITextAttr *textAttr = aTextAttrArray[idx];
if (!textAttr->Equal(currElm)) {
PRInt32 endHTOffset = 0;
nsresult rv = mHyperTextAcc->
DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (endHTOffset < *aEndHTOffset)
*aEndHTOffset = endHTOffset;
stop = PR_TRUE;
break;
}
}
if (stop)
break;
if (moveIntoSubtree) {
// Navigate through subtree of traversed node. We use 'moveIntoSubtree'
// flag to avoid traversing the same subtree twice.
currNode->GetFirstChild(getter_AddRefs(tmpNode));
if (tmpNode)
FindEndOffsetInSubtree(aTextAttrArray, tmpNode, aEndHTOffset);
}
currNode->GetNextSibling(getter_AddRefs(tmpNode));
moveIntoSubtree = PR_TRUE;
if (!tmpNode) {
currNode->GetParentNode(getter_AddRefs(tmpNode));
moveIntoSubtree = PR_FALSE;
}
currNode.swap(tmpNode);
}
return NS_OK;
}
PRBool
nsTextAttrsMgr::FindEndOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
nsIDOMNode *aCurrNode,
PRInt32 *aHTOffset)
{
if (!aCurrNode)
return PR_FALSE;
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
NS_ENSURE_STATE(currElm);
// If the given text attribute (pointed by nsTextAttr object) changes its
// value on the traversed element then fit the end of range.
PRUint32 len = aTextAttrArray.Length();
for (PRUint32 idx = 0; idx < len; idx++) {
nsITextAttr *textAttr = aTextAttrArray[idx];
if (!textAttr->Equal(currElm)) {
PRInt32 endHTOffset = 0;
nsresult rv = mHyperTextAcc->
DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
if (endHTOffset < *aHTOffset)
*aHTOffset = endHTOffset;
return PR_TRUE;
}
}
// Deeply traverse into the tree to fit the end of range.
nsCOMPtr<nsIDOMNode> nextNode;
aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
if (nextNode) {
PRBool res = FindEndOffsetInSubtree(aTextAttrArray, nextNode, aHTOffset);
if (res)
return res;
}
aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
if (nextNode) {
if (FindEndOffsetInSubtree(aTextAttrArray, nextNode, aHTOffset))
return PR_TRUE;
}
return PR_FALSE;
}
PRBool
nsTextAttrsMgr::FindStartOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
nsIDOMNode *aCurrNode,
nsIDOMNode *aPrevNode,
PRInt32 *aHTOffset)
{
if (!aCurrNode)
return PR_FALSE;
// Find the closest element back to the traversed element.
nsCOMPtr<nsIDOMNode> nextNode;
aCurrNode->GetLastChild(getter_AddRefs(nextNode));
if (nextNode) {
if (FindStartOffsetInSubtree(aTextAttrArray, nextNode, aPrevNode, aHTOffset))
return PR_TRUE;
}
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
NS_ENSURE_STATE(currElm);
// If the given text attribute (pointed by nsTextAttr object) changes its
// value on the traversed element then fit the start of range.
PRUint32 len = aTextAttrArray.Length();
for (PRUint32 idx = 0; idx < len; idx++) {
nsITextAttr *textAttr = aTextAttrArray[idx];
if (!textAttr->Equal(currElm)) {
PRInt32 startHTOffset = 0;
nsCOMPtr<nsIAccessible> startAcc;
nsresult rv = mHyperTextAcc->
DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
getter_AddRefs(startAcc));
NS_ENSURE_SUCCESS(rv, PR_FALSE);
if (!startAcc)
startHTOffset = 0;
if (startHTOffset > *aHTOffset)
*aHTOffset = startHTOffset;
return PR_TRUE;
}
}
// Moving backwards to find the start of range.
aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
if (nextNode) {
if (FindStartOffsetInSubtree(aTextAttrArray, nextNode, aCurrNode, aHTOffset))
return PR_TRUE;
}
return PR_FALSE;
}
////////////////////////////////////////////////////////////////////////////////
// nsLangTextAttr
nsLangTextAttr::nsLangTextAttr(nsHyperTextAccessible *aRootAcc,
nsIDOMNode *aRootNode, nsIDOMNode *aNode) :
nsTextAttr(aNode == nsnull)
{
mRootContent = do_QueryInterface(aRootNode);
nsresult rv = aRootAcc->GetLanguage(mRootNativeValue);
mIsRootDefined = NS_SUCCEEDED(rv) && !mRootNativeValue.IsEmpty();
if (aNode) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
mIsDefined = GetLang(content, mNativeValue);
}
}
PRBool
nsLangTextAttr::GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue)
{
nsCOMPtr<nsIContent> content = do_QueryInterface(aElm);
return GetLang(content, *aValue);
}
void
nsLangTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
{
aFormattedValue = aValue;
}
PRBool
nsLangTextAttr::GetLang(nsIContent *aContent, nsAString& aLang)
{
nsCoreUtils::GetLanguageFor(aContent, mRootContent, aLang);
return !aLang.IsEmpty();
}
////////////////////////////////////////////////////////////////////////////////
// nsCSSTextAttr
nsCSSTextAttr::nsCSSTextAttr(PRUint32 aIndex, nsIDOMElement *aRootElm,
nsIDOMElement *aElm) :
nsTextAttr(aElm == nsnull), mIndex(aIndex)
{
mIsRootDefined = GetValueFor(aRootElm, &mRootNativeValue);
if (aElm)
mIsDefined = GetValueFor(aElm, &mNativeValue);
}
nsIAtom*
nsCSSTextAttr::GetName()
{
return *gCSSTextAttrsMap[mIndex].mAttrName;
}
PRBool
nsCSSTextAttr::GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue)
{
nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
getter_AddRefs(currStyleDecl));
if (!currStyleDecl)
return PR_FALSE;
NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
nsresult rv = currStyleDecl->GetPropertyValue(cssName, *aValue);
if (NS_FAILED(rv))
return PR_TRUE;
const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
if (cssValue != kAnyValue && !aValue->EqualsASCII(cssValue))
return PR_FALSE;
return PR_TRUE;
}
void
nsCSSTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
{
const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
if (attrValue != kCopyValue)
AppendASCIItoUTF16(attrValue, aFormattedValue);
else
aFormattedValue = aValue;
}
////////////////////////////////////////////////////////////////////////////////
// nsBackgroundTextAttr
nsBGColorTextAttr::nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
nsTextAttr(aFrame == nsnull), mRootFrame(aRootFrame)
{
mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
if (aFrame)
mIsDefined = GetColor(aFrame, &mNativeValue);
}
PRBool
nsBGColorTextAttr::GetValueFor(nsIDOMElement *aElm, nscolor *aValue)
{
nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
if (!frame)
return PR_FALSE;
return GetColor(frame, aValue);
}
void
nsBGColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
{
// Combine the string like rgb(R, G, B) from nscolor.
nsAutoString value;
value.AppendLiteral("rgb(");
value.AppendInt(NS_GET_R(aValue));
value.AppendLiteral(", ");
value.AppendInt(NS_GET_G(aValue));
value.AppendLiteral(", ");
value.AppendInt(NS_GET_B(aValue));
value.Append(')');
aFormattedValue = value;
}
PRBool
nsBGColorTextAttr::GetColor(nsIFrame *aFrame, nscolor *aColor)
{
const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
if (!styleBackground->IsTransparent()) {
*aColor = styleBackground->mBackgroundColor;
return PR_TRUE;
}
nsIFrame *parentFrame = aFrame->GetParent();
if (!parentFrame) {
*aColor = aFrame->PresContext()->DefaultBackgroundColor();
return PR_TRUE;
}
// Each frame of parents chain for the initially passed 'aFrame' has
// transparent background color. So background color isn't changed from
// 'mRootFrame' to initially passed 'aFrame'.
if (parentFrame == mRootFrame)
return PR_FALSE;
return GetColor(parentFrame, aColor);
}
////////////////////////////////////////////////////////////////////////////////
// nsFontSizeTextAttr
nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
nsTextAttr(aFrame == nsnull)
{
mDC = aRootFrame->PresContext()->DeviceContext();
mRootNativeValue = GetFontSize(aRootFrame);
mIsRootDefined = PR_TRUE;
if (aFrame) {
mNativeValue = GetFontSize(aFrame);
mIsDefined = PR_TRUE;
}
}
PRBool
nsFontSizeTextAttr::GetValueFor(nsIDOMElement *aElm, nscoord *aValue)
{
nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
if (!frame)
return PR_FALSE;
*aValue = GetFontSize(frame);
return PR_TRUE;
}
void
nsFontSizeTextAttr::Format(const nscoord& aValue, nsAString& aFormattedValue)
{
// Convert from nscoord to pt.
//
// Note: according to IA2, "The conversion doesn't have to be exact.
// The intent is to give the user a feel for the size of the text."
//
// ATK does not specify a unit and will likely follow IA2 here.
//
// XXX todo: consider sharing this code with layout module? (bug 474621)
float inches = static_cast<float>(aValue) /
static_cast<float>(mDC->AppUnitsPerInch());
int pts = static_cast<int>(inches * 72 + .5); // 72 pts per inch
nsAutoString value;
value.AppendInt(pts);
value.Append(NS_LITERAL_STRING("pt"));
aFormattedValue = value;
}
nscoord
nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
{
nsStyleFont* styleFont =
(nsStyleFont*)(aFrame->GetStyleDataExternal(eStyleStruct_Font));
return styleFont->mSize;
}

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

@ -0,0 +1,371 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsTextAttrs_h_
#define nsTextAttrs_h_
class nsHyperTextAccessible;
#include "nsAccessibilityAtoms.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsIContent.h"
#include "nsIFrame.h"
#include "nsIPersistentProperties2.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsTPtrArray.h"
class nsITextAttr;
/**
* Used to expose text attributes for the hyper text accessible (see
* nsHyperTextAccessible class). It is indended for the work with 'language' and
* CSS based text attributes.
*
* @note "invalid: spelling" text attrbiute is implemented entirerly in
* nsHyperTextAccessible class.
*/
class nsTextAttrsMgr
{
public:
/**
* Constructor. If instance of the class is intended to expose default text
* attributes then 'aIncludeDefAttrs' and 'oOffsetNode' argument must be
* skiped.
*
* @param aHyperTextAcc hyper text accessible text attributes are
* calculated for
* @param aHyperTextNode DOM node of the given hyper text accessbile
* @param aIncludeDefAttrs [optional] indicates whether default text
* attributes should be included into list of exposed
* text attributes.
* @param oOffsetNode [optional] DOM node represents hyper text offset
* inside hyper text accessible
*/
nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
nsIDOMNode *aHyperTextNode,
PRBool aIncludeDefAttrs = PR_TRUE,
nsIDOMNode *oOffsetNode = nsnull);
/*
* Return text attributes and hyper text offsets where these attributes are
* applied. Offsets are calculated in the case of non default attributes.
*
* @note In the case of default attributes pointers on hyper text offsets
* must be skiped.
*
* @param aAttributes [in, out] text attributes list
* @param aStartHTOffset [out, optional] start hyper text offset
* @param aEndHTOffset [out, optional] end hyper text offset
*/
nsresult GetAttributes(nsIPersistentProperties *aAttributes,
PRInt32 *aStartHTOffset = nsnull,
PRInt32 *aEndHTOffset = nsnull);
protected:
/**
* Calculates range (start and end offsets) of text where the text attributes
* are stretched. New offsets may be smaller if one of text attributes changes
* its value before or after the given offsets.
*
* @param aTextAttrArray [in] text attributes array
* @param aStartHTOffset [in, out] the start offset
* @param aEndHTOffset [in, out] the end offset
*/
nsresult GetRange(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset);
/*
* Find new end offset for text attributes navigating through the tree. New
* end offset may be smaller if one of text attributes changes its value
* before the given end offset.
*
* @param aTextAttrArray [in] text attributes array
* @param aCurrNode [in] the first node of the tree
* @param aHTOffset [in, out] the end offset
* @return true if the end offset has been changed
*/
PRBool FindEndOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
nsIDOMNode *aCurrNode, PRInt32 *aHTOffset);
/*
* Find the start offset for text attributes navigating through the tree. New
* start offset may be bigger if one of text attributes changes its value
* after the given start offset.
*
* @param aTextAttrArray [in] text attributes array
* @param aCurrNode [in] the node navigating through thee thee is
* started from
* @param aPrevNode [in] the previous node placed before the start node
* @param aHTOffset [in, out] the start offset
* @return true if the start offset has been changed
*/
PRBool FindStartOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
nsIDOMNode *aCurrNode, nsIDOMNode *aPrevNode,
PRInt32 *aHTOffset);
private:
nsRefPtr<nsHyperTextAccessible> mHyperTextAcc;
nsCOMPtr<nsIDOMNode> mHyperTextNode;
PRBool mIncludeDefAttrs;
nsCOMPtr<nsIDOMNode> mOffsetNode;
};
////////////////////////////////////////////////////////////////////////////////
// Private implementation details
/**
* Interface class of text attribute class implementations.
*/
class nsITextAttr
{
public:
/**
* Return the name of text attribute.
*/
virtual nsIAtom* GetName() = 0;
/**
* Retrieve the value of text attribute in out param, return true if differs
* from the default value of text attribute or if include default attribute
* value flag is setted.
*
* @param aValue [in, out] the value of text attribute
* @param aIncludeDefAttrValue [in] include default attribute value flag
* @return true if text attribute value differs from
* default or include default attribute value
* flag is applied
*/
virtual PRBool GetValue(nsAString& aValue, PRBool aIncludeDefAttrValue) = 0;
/**
* Return true if the text attribute value on the given element equals with
* predefined attribute value.
*/
virtual PRBool Equal(nsIDOMElement *aElm) = 0;
};
/**
* Base class to work with text attributes. See derived classes below.
*/
template<class T>
class nsTextAttr : public nsITextAttr
{
public:
nsTextAttr(PRBool aGetRootValue) : mGetRootValue(aGetRootValue) {}
// nsITextAttr
virtual PRBool GetValue(nsAString& aValue, PRBool aIncludeDefAttrValue)
{
if (mGetRootValue) {
Format(mRootNativeValue, aValue);
return mIsRootDefined;
}
PRBool isDefined = mIsDefined;
T* nativeValue = &mNativeValue;
if (!isDefined) {
if (aIncludeDefAttrValue) {
isDefined = mIsRootDefined;
nativeValue = &mRootNativeValue;
}
} else if (!aIncludeDefAttrValue) {
isDefined = mRootNativeValue != mNativeValue;
}
if (!isDefined)
return PR_FALSE;
Format(*nativeValue, aValue);
return PR_TRUE;
}
virtual PRBool Equal(nsIDOMElement *aElm)
{
T nativeValue;
PRBool isDefined = GetValueFor(aElm, &nativeValue);
if (!mIsDefined && !isDefined)
return PR_TRUE;
if (mIsDefined && isDefined)
return nativeValue == mNativeValue;
if (mIsDefined)
return mNativeValue == mRootNativeValue;
return nativeValue == mRootNativeValue;
}
protected:
// Return native value for the given DOM element.
virtual PRBool GetValueFor(nsIDOMElement *aElm, T *aValue) = 0;
// Format native value to text attribute value.
virtual void Format(const T& aValue, nsAString& aFormattedValue) = 0;
// Indicates if root value should be exposed.
PRBool mGetRootValue;
// Native value and flag indicating if the value is defined (initialized in
// derived classes). Note, undefined native value means it is inherited
// from root.
T mNativeValue;
PRBool mIsDefined;
// Native root value and flag indicating if the value is defined (initialized
// in derived classes).
T mRootNativeValue;
PRBool mIsRootDefined;
};
/**
* Class is used for the work with 'language' text attribute in nsTextAttrsMgr
* class.
*/
class nsLangTextAttr : public nsTextAttr<nsAutoString>
{
public:
nsLangTextAttr(nsHyperTextAccessible *aRootAcc, nsIDOMNode *aRootNode,
nsIDOMNode *aNode);
// nsITextAttr
virtual nsIAtom *GetName() { return nsAccessibilityAtoms::language; }
protected:
// nsTextAttr
virtual PRBool GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue);
virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
private:
PRBool GetLang(nsIContent *aContent, nsAString& aLang);
nsCOMPtr<nsIContent> mRootContent;
};
/**
* Class is used for the work with CSS based text attributes in nsTextAttrsMgr
* class.
*/
class nsCSSTextAttr : public nsTextAttr<nsAutoString>
{
public:
nsCSSTextAttr(PRUint32 aIndex, nsIDOMElement *aRootElm, nsIDOMElement *aElm);
// nsITextAttr
virtual nsIAtom *GetName();
protected:
// nsTextAttr
virtual PRBool GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue);
virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
private:
PRInt32 mIndex;
};
/**
* Class is used for the work with 'background-color' text attribute in
* nsTextAttrsMgr class.
*/
class nsBGColorTextAttr : public nsTextAttr<nscolor>
{
public:
nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
// nsITextAttr
virtual nsIAtom *GetName() { return nsAccessibilityAtoms::backgroundColor; }
protected:
// nsTextAttr
virtual PRBool GetValueFor(nsIDOMElement *aElm, nscolor *aValue);
virtual void Format(const nscolor& aValue, nsAString& aFormattedValue);
private:
PRBool GetColor(nsIFrame *aFrame, nscolor *aColor);
nsIFrame *mRootFrame;
};
/**
* Class is used for the work with "font-size" text attribute in nsTextAttrsMgr
* class.
*/
class nsFontSizeTextAttr : public nsTextAttr<nscoord>
{
public:
nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
// nsITextAttr
virtual nsIAtom *GetName() { return nsAccessibilityAtoms::fontSize; }
protected:
// nsTextAttr
virtual PRBool GetValueFor(nsIDOMElement *aElm, nscoord *aValue);
virtual void Format(const nscoord& aValue, nsAString& aFormattedValue);
private:
/**
* Return font size for the given frame.
*
* @param aFrame [in] the given frame to query font-size
* @return font size
*/
nscoord GetFontSize(nsIFrame *aFrame);
nsIDeviceContext *mDC;
};
#endif

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

@ -1,298 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsTextUtils.h"
#include "nsAccessNode.h"
////////////////////////////////////////////////////////////////////////////////
// nsLangTextAttr
PRBool
nsLangTextAttr::Equal(nsIDOMElement *aElm)
{
nsCOMPtr<nsIContent> content(do_QueryInterface(aElm));
if (!content)
return PR_FALSE;
nsAutoString lang;
nsCoreUtils::GetLanguageFor(content, mRootContent, lang);
return lang == mLang;
}
////////////////////////////////////////////////////////////////////////////////
// nsCSSTextAttr
/**
* Item of the gCSSTextAttrsMap map.
*/
struct nsCSSTextAttrMapItem
{
const char* mCSSName;
const char* mCSSValue;
const char* mAttrName;
const char* mAttrValue;
};
/**
* The map of CSS properties to text attributes.
*/
const char* const kAnyValue = nsnull;
const char* const kCopyName = nsnull;
const char* const kCopyValue = nsnull;
static nsCSSTextAttrMapItem gCSSTextAttrsMap[] = {
// CSS name CSS value Attribute name Attribute value
{ "color", kAnyValue, kCopyName, kCopyValue },
{ "font-family", kAnyValue, kCopyName, kCopyValue },
{ "font-style", kAnyValue, kCopyName, kCopyValue },
{ "font-weight", kAnyValue, kCopyName, kCopyValue },
{ "text-decoration", "line-through", "text-line-through-style", "solid" },
{ "text-decoration", "underline", "text-underline-style", "solid" },
{ "vertical-align", kAnyValue, "text-position", kCopyValue }
};
nsCSSTextAttr::nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
nsIDOMElement *aRootElm) :
mIndex(-1), mIncludeDefAttrValue(aIncludeDefAttrValue)
{
nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
getter_AddRefs(mStyleDecl));
if (!mIncludeDefAttrValue)
nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aRootElm,
getter_AddRefs(mDefStyleDecl));
}
PRBool
nsCSSTextAttr::Equal(nsIDOMElement *aElm)
{
if (!aElm || !mStyleDecl)
return PR_FALSE;
nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
getter_AddRefs(currStyleDecl));
if (!currStyleDecl)
return PR_FALSE;
NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
nsAutoString currValue;
nsresult rv = currStyleDecl->GetPropertyValue(cssName, currValue);
if (NS_FAILED(rv))
return PR_FALSE;
nsAutoString value;
rv = mStyleDecl->GetPropertyValue(cssName, value);
return NS_SUCCEEDED(rv) && value == currValue;
}
PRBool
nsCSSTextAttr::Iterate()
{
return ++mIndex < static_cast<PRInt32>(NS_ARRAY_LENGTH(gCSSTextAttrsMap));
}
PRBool
nsCSSTextAttr::Get(nsACString& aName, nsAString& aValue)
{
if (!mStyleDecl)
return PR_FALSE;
NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
nsresult rv = mStyleDecl->GetPropertyValue(cssName, aValue);
if (NS_FAILED(rv))
return PR_FALSE;
// Don't expose text attribute if corresponding CSS value on the element
// equals to CSS value on the root element and we don't want to include
// default values.
if (!mIncludeDefAttrValue) {
if (!mDefStyleDecl)
return PR_FALSE;
nsAutoString defValue;
mDefStyleDecl->GetPropertyValue(cssName, defValue);
if (defValue == aValue)
return PR_FALSE;
}
// Don't expose text attribute if its required specific CSS value isn't
// matched with the CSS value we got.
const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
if (cssValue != kAnyValue && !aValue.EqualsASCII(cssValue))
return PR_FALSE;
// Get the name of text attribute.
if (gCSSTextAttrsMap[mIndex].mAttrName != kCopyName)
aName = gCSSTextAttrsMap[mIndex].mAttrName;
else
aName = gCSSTextAttrsMap[mIndex].mCSSName;
// Get the value of text attribute.
const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
if (attrValue != kCopyValue)
AppendASCIItoUTF16(attrValue, aValue);
return PR_TRUE;
}
////////////////////////////////////////////////////////////////////////////////
// nsBackgroundTextAttr
nsBackgroundTextAttr::nsBackgroundTextAttr(nsIFrame *aFrame,
nsIFrame *aRootFrame) :
mFrame(aFrame), mRootFrame(aRootFrame)
{
}
PRBool
nsBackgroundTextAttr::Equal(nsIDOMElement *aElm)
{
nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
if (!frame)
return PR_FALSE;
return GetColor(mFrame) == GetColor(frame);
}
PRBool
nsBackgroundTextAttr::Get(nsAString& aValue)
{
// Do not expose "background-color" text attribute if its value is matched
// with the default value.
nscolor color = GetColor(mFrame);
if (mRootFrame && color == GetColor(mRootFrame))
return PR_FALSE;
// Combine the string like rgb(R, G, B) from nscolor.
nsAutoString value;
value.AppendLiteral("rgb(");
value.AppendInt(NS_GET_R(color));
value.AppendLiteral(", ");
value.AppendInt(NS_GET_G(color));
value.AppendLiteral(", ");
value.AppendInt(NS_GET_B(color));
value.Append(')');
aValue = value;
return PR_TRUE;
}
nscolor
nsBackgroundTextAttr::GetColor(nsIFrame *aFrame)
{
const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
if (!styleBackground->IsTransparent())
return styleBackground->mBackgroundColor;
nsIFrame *parentFrame = aFrame->GetParent();
if (!parentFrame)
return aFrame->PresContext()->DefaultBackgroundColor();
// Each frame of parents chain for the initially passed 'aFrame' has
// transparent background color. So background color isn't changed from
// 'mRootFrame' to initially passed 'aFrame'.
if (parentFrame == mRootFrame)
return GetColor(mRootFrame);
return GetColor(parentFrame);
}
////////////////////////////////////////////////////////////////////////////////
// nsFontSizeTextAttr
nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aFrame,
nsIFrame *aRootFrame) :
mFrame(aFrame), mRootFrame(aRootFrame)
{
}
PRBool
nsFontSizeTextAttr::Equal(nsIDOMElement *aElm)
{
nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
if (!frame)
return PR_FALSE;
return GetFontSize(mFrame) == GetFontSize(frame);
}
PRBool
nsFontSizeTextAttr::Get(nsAString& aValue)
{
// Do not expose "font-size" text attribute if its value is the same
// as the default value.
nscoord fontsize = GetFontSize(mFrame);
if (mRootFrame && fontsize == GetFontSize(mRootFrame))
return PR_FALSE;
// Convert from nscoord to pt.
//
// Note: according to IA2, "The conversion doesn't have to be exact.
// The intent is to give the user a feel for the size of the text."
//
// ATK does not specify a unit and will likely follow IA2 here.
//
// XXX todo: consider sharing this code with layout module? (bug 474621)
nsIDeviceContext *dc = mFrame->PresContext()->DeviceContext();
float inches = static_cast<float>(GetFontSize(mFrame)) /
static_cast<float>(dc->AppUnitsPerInch());
int pts = inches * 72 + .5; // 72 pts per inch
nsAutoString value;
value.AppendInt(pts);
value.Append(NS_LITERAL_STRING("pt"));
aValue = value;
return PR_TRUE;
}
nscoord
nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
{
nsStyleFont* styleFont =
(nsStyleFont*)(aFrame->GetStyleDataExternal(eStyleStruct_Font));
return styleFont->mSize;
}

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

@ -1,190 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsTextUtils_h_
#define nsTextUtils_h_
#include "nsIDOMElement.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsIContent.h"
#include "nsIFrame.h"
#include "nsCOMPtr.h"
#include "nsString.h"
/**
* Base class to work with text attributes. See derived classes below.
*/
class nsTextAttr
{
public:
/**
* Return true if the text attribute for the given element equals with
* predefined attribute.
*/
virtual PRBool Equal(nsIDOMElement *aElm) = 0;
};
/**
* Class is used for the work with 'lang' text attributes. Used in
* nsHyperTextAccessible.
*/
class nsLangTextAttr : public nsTextAttr
{
public:
nsLangTextAttr(nsAString& aLang, nsIContent *aRootContent) :
mLang(aLang), mRootContent(aRootContent) { }
virtual PRBool Equal(nsIDOMElement *aElm);
private:
nsString mLang;
nsCOMPtr<nsIContent> mRootContent;
};
/**
* Class is used for the work with CSS based text attributes. Used in
* nsHyperTextAccessible.
*/
class nsCSSTextAttr : public nsTextAttr
{
public:
nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
nsIDOMElement *aRootElm);
// nsTextAttr
virtual PRBool Equal(nsIDOMElement *aElm);
// nsCSSTextAttr
/**
* Interates through attributes.
*/
PRBool Iterate();
/**
* Get name and value of attribute.
*/
PRBool Get(nsACString& aName, nsAString& aValue);
private:
PRInt32 mIndex;
PRBool mIncludeDefAttrValue;
nsCOMPtr<nsIDOMCSSStyleDeclaration> mStyleDecl;
nsCOMPtr<nsIDOMCSSStyleDeclaration> mDefStyleDecl;
};
/**
* Class is used for the work with "background-color" text attribute. It is
* used in nsHyperTextAccessible.
*/
class nsBackgroundTextAttr : public nsTextAttr
{
public:
nsBackgroundTextAttr(nsIFrame *aFrame, nsIFrame *aRootFrame);
// nsTextAttr
virtual PRBool Equal(nsIDOMElement *aElm);
// nsBackgroundTextAttr
/**
* Retrieve the "background-color" in out param, return true if differs from
* the default background-color.
*
* @param aValue [out] the background color in pts
* @return true if background color differs from default
*/
virtual PRBool Get(nsAString& aValue);
private:
/**
* Return background color for the given frame.
*
* @note If background color for the given frame is transparent then walk
* trhough the frame parents chain until we'll got either a frame with
* not transparent background color or the given root frame. In the
* last case return background color for the root frame.
*
* @param aFrame [in] the given frame to calculate background-color
* @return background color
*/
nscolor GetColor(nsIFrame *aFrame);
nsIFrame *mFrame;
nsIFrame *mRootFrame;
};
/**
* Class is used for the work with "font-size" text attribute. It is
* used in nsHyperTextAccessible.
*/
class nsFontSizeTextAttr : public nsTextAttr
{
public:
nsFontSizeTextAttr(nsIFrame *aFrame, nsIFrame *aRootFrame);
// nsTextAttr
virtual PRBool Equal(nsIDOMElement *aElm);
// nsFontSizeTextAttr
/**
* Retrieve the "font-size" in out param, return true if differs from
* the default font-size.
*
* @param aValue [out] the font size in pts
* @return true if font size differs from default
*/
virtual PRBool Get(nsAString& aValue);
private:
/**
* Return font size for the given frame.
*
* @param aFrame [in] the given frame to query font-size
* @return font size
*/
nscoord GetFontSize(nsIFrame *aFrame);
nsIFrame *mFrame;
nsIFrame *mRootFrame;
};
#endif

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

@ -41,7 +41,7 @@
#include "nsAccessibilityAtoms.h"
#include "nsAccessibilityService.h"
#include "nsAccessibleTreeWalker.h"
#include "nsTextUtils.h"
#include "nsTextAttrs.h"
#include "nsIClipboard.h"
#include "nsContentCID.h"
@ -1174,17 +1174,8 @@ nsHyperTextAccessible::GetTextAttributes(PRBool aIncludeDefAttrs,
if (!node)
return NS_OK;
// Set 'lang' text attribute.
rv = GetLangTextAttributes(aIncludeDefAttrs, node,
aStartOffset, aEndOffset,
aAttributes ? *aAttributes : nsnull);
NS_ENSURE_SUCCESS(rv, rv);
// Set CSS based text attributes.
rv = GetCSSTextAttributes(aIncludeDefAttrs, node,
aStartOffset, aEndOffset,
aAttributes ? *aAttributes : nsnull);
return rv;
nsTextAttrsMgr textAttrsMgr(this, mDOMNode, aIncludeDefAttrs, node);
return textAttrsMgr.GetAttributes(*aAttributes, aStartOffset, aEndOffset);
}
// nsIPersistentProperties
@ -1204,35 +1195,8 @@ nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttri
if (!mDOMNode)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMElement> element = nsCoreUtils::GetDOMElementFor(mDOMNode);
nsCSSTextAttr textAttr(PR_TRUE, element, nsnull);
while (textAttr.Iterate()) {
nsCAutoString name;
nsAutoString value, oldValue;
if (textAttr.Get(name, value))
attributes->SetStringProperty(name, value, oldValue);
}
nsIFrame *sourceFrame = nsCoreUtils::GetFrameFor(element);
NS_ENSURE_STATE(sourceFrame);
// set font size
nsAutoString value;
nsFontSizeTextAttr fontSizeTextAttr(sourceFrame, nsnull);
fontSizeTextAttr.Get(value);
nsAccUtils::SetAccAttr(attributes,
nsAccessibilityAtoms::fontSize, value);
value.Truncate();
// set font background color
nsBackgroundTextAttr backgroundTextAttr(sourceFrame, nsnull);
backgroundTextAttr.Get(value);
nsAccUtils::SetAccAttr(attributes,
nsAccessibilityAtoms::backgroundColor, value);
return NS_OK;
nsTextAttrsMgr textAttrsMgr(this, mDOMNode, PR_TRUE, nsnull);
return textAttrsMgr.GetAttributes(*aAttributes);
}
nsresult
@ -2320,275 +2284,3 @@ nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode,
return NS_OK;
}
// nsHyperTextAccessible
nsresult
nsHyperTextAccessible::GetLangTextAttributes(PRBool aIncludeDefAttrs,
nsIDOMNode *aSourceNode,
PRInt32 *aStartHTOffset,
PRInt32 *aEndHTOffset,
nsIPersistentProperties *aAttributes)
{
nsCOMPtr<nsIDOMElement> sourceElm(nsCoreUtils::GetDOMElementFor(aSourceNode));
nsCOMPtr<nsIContent> content(do_QueryInterface(sourceElm));
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(mDOMNode));
nsAutoString lang;
nsCoreUtils::GetLanguageFor(content, rootContent, lang);
nsAutoString rootLang;
nsresult rv = GetLanguage(rootLang);
NS_ENSURE_SUCCESS(rv, rv);
if (aAttributes) {
// Expose 'language' text attribute if the DOM 'lang' attribute is
// presented and it's different from the 'lang' attribute on the root
// element or we should include default values of text attribute.
const nsAString& resultLang = lang.IsEmpty() ? rootLang : lang;
if (!resultLang.IsEmpty() && (aIncludeDefAttrs || lang != rootLang))
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::language,
resultLang);
}
nsLangTextAttr textAttr(lang, rootContent);
return GetRangeForTextAttr(aSourceNode, &textAttr,
aStartHTOffset, aEndHTOffset);
}
// nsHyperTextAccessible
nsresult
nsHyperTextAccessible::GetCSSTextAttributes(PRBool aIncludeDefAttrs,
nsIDOMNode *aSourceNode,
PRInt32 *aStartHTOffset,
PRInt32 *aEndHTOffset,
nsIPersistentProperties *aAttributes)
{
nsCOMPtr<nsIDOMElement> sourceElm(nsCoreUtils::GetDOMElementFor(aSourceNode));
nsCOMPtr<nsIDOMElement> rootElm(nsCoreUtils::GetDOMElementFor(mDOMNode));
nsCSSTextAttr textAttr(aIncludeDefAttrs, sourceElm, rootElm);
while (textAttr.Iterate()) {
nsCAutoString name;
nsAutoString value, oldValue;
if (aAttributes && textAttr.Get(name, value))
aAttributes->SetStringProperty(name, value, oldValue);
nsresult rv = GetRangeForTextAttr(aSourceNode, &textAttr,
aStartHTOffset, aEndHTOffset);
NS_ENSURE_SUCCESS(rv, rv);
}
nsIFrame *sourceFrame = nsCoreUtils::GetFrameFor(sourceElm);
if (sourceFrame) {
nsIFrame *rootFrame = nsnull;
if (!aIncludeDefAttrs)
rootFrame = nsCoreUtils::GetFrameFor(rootElm);
nsFontSizeTextAttr fontSizeTextAttr(sourceFrame, rootFrame);
nsAutoString value;
if (fontSizeTextAttr.Get(value)) {
nsAccUtils::SetAccAttr(aAttributes,
nsAccessibilityAtoms::fontSize, value);
}
nsBackgroundTextAttr backgroundTextAttr(sourceFrame, rootFrame);
value.Truncate();
if (backgroundTextAttr.Get(value)) {
nsAccUtils::SetAccAttr(aAttributes,
nsAccessibilityAtoms::backgroundColor, value);
}
nsresult rv = GetRangeForTextAttr(aSourceNode, &backgroundTextAttr,
aStartHTOffset, aEndHTOffset);
return rv;
}
return NS_OK;
}
// nsHyperTextAccessible
nsresult
nsHyperTextAccessible::GetRangeForTextAttr(nsIDOMNode *aNode,
nsTextAttr *aComparer,
PRInt32 *aStartHTOffset,
PRInt32 *aEndHTOffset)
{
nsCOMPtr<nsIDOMElement> rootElm(nsCoreUtils::GetDOMElementFor(mDOMNode));
NS_ENSURE_STATE(rootElm);
nsCOMPtr<nsIDOMNode> tmpNode(aNode);
nsCOMPtr<nsIDOMNode> currNode(aNode);
// Navigate backwards and forwards from current node to the root node to
// calculate range bounds for the text attribute. Navigation sequence is the
// following:
// 1. Navigate through the siblings.
// 2. If the traversed sibling has children then navigate from its leaf child
// to it through whole tree of the traversed sibling.
// 3. Get the parent and cycle algorithm until the root node.
// Navigate backwards (find the start offset).
while (currNode && currNode != rootElm) {
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
NS_ENSURE_STATE(currElm);
if (currNode != aNode && !aComparer->Equal(currElm)) {
PRInt32 startHTOffset = 0;
nsCOMPtr<nsIAccessible> startAcc;
nsresult rv = DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
getter_AddRefs(startAcc));
NS_ENSURE_SUCCESS(rv, rv);
if (!startAcc)
startHTOffset = 0;
if (startHTOffset > *aStartHTOffset)
*aStartHTOffset = startHTOffset;
break;
}
currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
if (tmpNode) {
// Navigate through the subtree of traversed children to calculate
// left bound of the range.
FindStartOffsetInSubtree(tmpNode, currNode, aComparer, aStartHTOffset);
}
currNode->GetParentNode(getter_AddRefs(tmpNode));
currNode.swap(tmpNode);
}
// Navigate forwards (find the end offset).
PRBool moveIntoSubtree = PR_TRUE;
currNode = aNode;
while (currNode && currNode != rootElm) {
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
NS_ENSURE_STATE(currElm);
// Stop new end offset searching if the given text attribute changes its
// value.
if (!aComparer->Equal(currElm)) {
PRInt32 endHTOffset = 0;
nsresult rv = DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (endHTOffset < *aEndHTOffset)
*aEndHTOffset = endHTOffset;
break;
}
if (moveIntoSubtree) {
// Navigate through subtree of traversed node. We use 'moveIntoSubtree'
// flag to avoid traversing the same subtree twice.
currNode->GetFirstChild(getter_AddRefs(tmpNode));
if (tmpNode)
FindEndOffsetInSubtree(tmpNode, aComparer, aEndHTOffset);
}
currNode->GetNextSibling(getter_AddRefs(tmpNode));
moveIntoSubtree = PR_TRUE;
if (!tmpNode) {
currNode->GetParentNode(getter_AddRefs(tmpNode));
moveIntoSubtree = PR_FALSE;
}
currNode.swap(tmpNode);
}
return NS_OK;
}
PRBool
nsHyperTextAccessible::FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
nsTextAttr *aComparer,
PRInt32 *aHTOffset)
{
if (!aCurrNode)
return PR_FALSE;
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
NS_ENSURE_STATE(currElm);
// If the given text attribute (pointed by nsTextAttr object) changes its
// value on the traversed element then fit the end of range.
if (!aComparer->Equal(currElm)) {
PRInt32 endHTOffset = 0;
nsresult rv = DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (endHTOffset < *aHTOffset)
*aHTOffset = endHTOffset;
return PR_TRUE;
}
// Deeply traverse into the tree to fit the end of range.
nsCOMPtr<nsIDOMNode> nextNode;
aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
if (nextNode) {
PRBool res = FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset);
if (res)
return res;
}
aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
if (nextNode) {
if (FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset))
return PR_TRUE;
}
return PR_FALSE;
}
PRBool
nsHyperTextAccessible::FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
nsIDOMNode *aPrevNode,
nsTextAttr *aComparer,
PRInt32 *aHTOffset)
{
if (!aCurrNode)
return PR_FALSE;
// Find the closest element back to the traversed element.
nsCOMPtr<nsIDOMNode> nextNode;
aCurrNode->GetLastChild(getter_AddRefs(nextNode));
if (nextNode) {
if (FindStartOffsetInSubtree(nextNode, aPrevNode, aComparer, aHTOffset))
return PR_TRUE;
}
nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
NS_ENSURE_STATE(currElm);
// If the given text attribute (pointed by nsTextAttr object) changes its
// value on the traversed element then fit the start of range.
if (!aComparer->Equal(currElm)) {
PRInt32 startHTOffset = 0;
nsCOMPtr<nsIAccessible> startAcc;
nsresult rv = DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
getter_AddRefs(startAcc));
NS_ENSURE_SUCCESS(rv, rv);
if (!startAcc)
startHTOffset = 0;
if (startHTOffset > *aHTOffset)
*aHTOffset = startHTOffset;
return PR_TRUE;
}
// Moving backwards to find the start of range.
aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
if (nextNode) {
if (FindStartOffsetInSubtree(nextNode, aCurrNode, aComparer, aHTOffset))
return PR_TRUE;
}
return PR_FALSE;
}

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

@ -45,7 +45,7 @@
#include "nsIAccessibleHyperText.h"
#include "nsIAccessibleEditableText.h"
#include "nsAccessibleEventData.h"
#include "nsTextUtils.h"
#include "nsTextAttrs.h"
#include "nsFrameSelection.h"
#include "nsISelectionController.h"
@ -293,88 +293,6 @@ protected:
PRInt32 *aStartOffset,
PRInt32 *aEndOffset,
nsIPersistentProperties *aAttributes);
/**
* Set 'lang' text attribute and return range offsets where attibute is
* stretched. The method is used by GetTextAttributes() method.
*
* @param aIncludeDefAttrs [in] points whether text attributes having default
* values of attributes should be included
* @param aSourceNode [in] the node we start to traverse from
* @param aStartOffset [in, out] the start offset
* @param aEndOffset [in, out] the end offset
* @param aAttributes [out, optional] result attributes
*/
nsresult GetLangTextAttributes(PRBool aIncludeDefAttrs,
nsIDOMNode *aSourceNode,
PRInt32 *aStartOffset,
PRInt32 *aEndOffset,
nsIPersistentProperties *aAttributes);
/**
* Set CSS based text attribute and return range offsets where attibutes are
* stretched. The method is used by GetTextAttributes() method.
*
* @param aIncludeDefAttrs [in] points whether text attributes having default
* values of attributes should be included
* @param aSourceNode [in] the node we start to traverse from
* @param aStartOffset [in, out] the start offset
* @param aEndOffset [in, out] the end offset
* @param aAttributes [out, optional] result attributes
*/
nsresult GetCSSTextAttributes(PRBool aIncludeDefAttrs,
nsIDOMNode *aSourceNode,
PRInt32 *aStartOffset,
PRInt32 *aEndOffset,
nsIPersistentProperties *aAttributes);
/**
* Calculates range (start and end offsets) of text where the text attribute
* (pointed by nsTextAttr object) is stretched. New offsets may be smaller if
* the given text attribute changes its value before or after the given
* offsets.
*
* @param aNode [in] the node we start to traverse from
* @param aComparer [in] object used to describe the text attribute
* @param aStartHTOffset [in, out] the start offset
* @param aEndHTOffset [in, out] the end offset
*/
nsresult GetRangeForTextAttr(nsIDOMNode *aNode,
nsTextAttr *aComparer,
PRInt32 *aStartHTOffset,
PRInt32 *aEndHTOffset);
/**
* Find new end offset for text attributes navigating through the tree. New
* end offset may be smaller if the given text attribute (pointed by
* nsTextAttr object) changes its value before the given end offset.
*
* @param aCurrNode [in] the first node of the tree
* @param aComparer [in] object used to describe the text attribute
* @param aHTOffset [in, out] the end offset
* @return true if the end offset has been changed
*/
PRBool FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
nsTextAttr *aComparer,
PRInt32 *aHTOffset);
/**
* Find the start offset for text attributes navigating through the tree. New
* start offset may be bigger if the given text attribute (pointed by
* nsTextAttr object) changes its value after the given start offset.
*
* @param aCurrNode [in] the node navigating through thee thee is started
* from
* @param aPrevNode [in] the previous node placed before the start node
* @param aComparer [in] object used to describe the text attribute
* @param aHTOffset [in, out] the start offset
* @return true if the start offset has been changed
*/
PRBool FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
nsIDOMNode *aPrevNode,
nsTextAttr *aComparer,
PRInt32 *aHTOffset);
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,

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

@ -62,7 +62,10 @@ function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
* @param aOffset [in] the offset inside text accessible to fetch
* text attributes
* @param aAttrs [in] the map of expected text attributes
* (name/value pairs)
* (name/value pairs) exposed at the offset
* @param aDefAttrs [in] the map of expected text attributes
* (name/value pairs) exposed on hyper text
* accessible
* @param aStartOffset [in] expected start offset where text attributes
* are applied
* @param aEndOffset [in] expected end offset where text attribute
@ -70,8 +73,8 @@ function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
* @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
* unexpected attribute is encountered
*/
function testTextAttrs(aID, aOffset, aAttrs, aStartOffset, aEndOffset,
aSkipUnexpectedAttrs)
function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
aStartOffset, aEndOffset, aSkipUnexpectedAttrs)
{
var accessible = getAccessible(aID, [nsIAccessibleText]);
if (!accessible)
@ -79,17 +82,13 @@ function testTextAttrs(aID, aOffset, aAttrs, aStartOffset, aEndOffset,
var startOffset = { value: -1 };
var endOffset = { value: -1 };
var attrs = null;
try {
attrs = accessible.getTextAttributes(false, aOffset,
startOffset, endOffset);
} catch (e) {
}
if (!attrs) {
ok(false, "Can't get text attributes for " + aID);
// do not include attributes exposed on hyper text accessbile
var attrs = getTextAttributes(aID, accessible, false, aOffset,
startOffset, endOffset);
if (!attrs)
return;
}
var errorMsg = " for " + aID + " at offset " + aOffset;
@ -97,6 +96,24 @@ function testTextAttrs(aID, aOffset, aAttrs, aStartOffset, aEndOffset,
is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg);
compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
// include attributes exposed on hyper text accessbile
var expectedAttrs = {};
for (var name in aAttrs)
expectedAttrs[name] = aAttrs[name];
for (var name in aDefAttrs) {
if (!(name in expectedAttrs))
expectedAttrs[name] = aDefAttrs[name];
}
attrs = getTextAttributes(aID, accessible, true, aOffset,
startOffset, endOffset);
if (!attrs)
return;
compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs);
}
/**
@ -133,6 +150,25 @@ function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs)
////////////////////////////////////////////////////////////////////////////////
// Private.
function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset,
aStartOffset, aEndOffset)
{
// This function expects the passed in accessible to already be queried for
// nsIAccessibleText.
var attrs = null;
try {
attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset,
aStartOffset, aEndOffset);
} catch (e) {
}
if (attrs)
return attrs;
ok(false, "Can't get text attributes for " + aID);
return null;
}
function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs)
{
var enumerate = aAttrs.enumerate();

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

@ -66,10 +66,10 @@
"invalid": "spelling"
};
testTextAttrs(ID, 0, attrs, 0, 11);
testTextAttrs(ID, 11, misspelledAttrs, 11, 17);
testTextAttrs(ID, 17, attrs, 17, 18);
testTextAttrs(ID, 18, misspelledAttrs, 18, 22);
testTextAttrs(ID, 0, attrs, defAttrs, 0, 11);
testTextAttrs(ID, 11, misspelledAttrs, defAttrs, 11, 17);
testTextAttrs(ID, 17, attrs, defAttrs, 17, 18);
testTextAttrs(ID, 18, misspelledAttrs, defAttrs, 18, 22);
is(gTextAttrChangedEventHandler.eventNumber, 2,
"Wrong count of 'text attribute changed' events for " + ID);
@ -101,15 +101,15 @@
testDefaultTextAttrs(ID, defAttrs);
var attrs = {};
testTextAttrs(ID, 0, attrs, 0, 7);
testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": gComputedStyle.fontWeight};
testTextAttrs(ID, 7, attrs, 7, 11);
testTextAttrs(ID, 7, attrs, defAttrs, 7, 11);
attrs = {};
testTextAttrs(ID, 12, attrs, 11, 18);
testTextAttrs(ID, 12, attrs, defAttrs, 11, 18);
//////////////////////////////////////////////////////////////////////////
// area2
@ -129,26 +129,26 @@
testDefaultTextAttrs(ID, defAttrs);
attrs = {};
testTextAttrs(ID, 0, attrs, 0, 7);
testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": gComputedStyle.fontWeight};
testTextAttrs(ID, 7, attrs, 7, 12);
testTextAttrs(ID, 7, attrs, defAttrs, 7, 12);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-style": gComputedStyle.fontStyle,
"font-weight": gComputedStyle.fontWeight};
testTextAttrs(ID, 13, attrs, 12, 19);
testTextAttrs(ID, 13, attrs, defAttrs, 12, 19);
tempElem = tempElem.parentNode;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": "401"};
testTextAttrs(ID, 20, attrs, 19, 23);
testTextAttrs(ID, 20, attrs, defAttrs, 19, 23);
attrs = {};
testTextAttrs(ID, 24, attrs, 23, 30);
testTextAttrs(ID, 24, attrs, defAttrs, 23, 30);
//////////////////////////////////////////////////////////////////////////
// area3
@ -170,23 +170,23 @@
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 0, attrs, 0, 6);
testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 6, attrs, 6, 26);
testTextAttrs(ID, 6, attrs, defAttrs, 6, 26);
tempElem = tempElem.parentNode;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 26, attrs, 26, 27);
testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
tempElem = tempElem.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color,
"background-color": gComputedStyle.backgroundColor};
testTextAttrs(ID, 27, attrs, 27, 50);
testTextAttrs(ID, 27, attrs, defAttrs, 27, 50);
//////////////////////////////////////////////////////////////////////////
// area4
@ -208,17 +208,17 @@
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 0, attrs, 0, 16);
testTextAttrs(ID, 0, attrs, defAttrs, 0, 16);
tempElem = tempElem.nextSibling.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 16, attrs, 16, 33);
testTextAttrs(ID, 16, attrs, defAttrs, 16, 33);
tempElem = tempElem.parentNode;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 34, attrs, 33, 46);
testTextAttrs(ID, 34, attrs, defAttrs, 33, 46);
//////////////////////////////////////////////////////////////////////////
// area5
@ -240,18 +240,18 @@
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 0, attrs, 0, 5);
testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
attrs = {};
testTextAttrs(ID, 7, attrs, 5, 8);
testTextAttrs(ID, 7, attrs, defAttrs, 5, 8);
tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 9, attrs, 8, 11);
testTextAttrs(ID, 9, attrs, defAttrs, 8, 11);
attrs = {};
testTextAttrs(ID, 11, attrs, 11, 18);
testTextAttrs(ID, 11, attrs, defAttrs, 11, 18);
//////////////////////////////////////////////////////////////////////////
// area6 (CSS vertical-align property, bug 445938)
@ -271,44 +271,165 @@
testDefaultTextAttrs(ID, defAttrs);
attrs = {};
testTextAttrs(ID, 0, attrs, 0, 5);
testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign,
"font-size": "10pt"};
testTextAttrs(ID, 5, attrs, 5, 13);
testTextAttrs(ID, 5, attrs, defAttrs, 5, 13);
attrs = {};
testTextAttrs(ID, 13, attrs, 13, 27);
testTextAttrs(ID, 13, attrs, defAttrs, 13, 27);
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign};
testTextAttrs(ID, 27, attrs, 27, 35);
testTextAttrs(ID, 27, attrs, defAttrs, 27, 35);
attrs = {};
testTextAttrs(ID, 35, attrs, 35, 39);
testTextAttrs(ID, 35, attrs, defAttrs, 35, 39);
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign,
"font-size": "10pt"};
testTextAttrs(ID, 39, attrs, 39, 50);
testTextAttrs(ID, 39, attrs, defAttrs, 39, 50);
attrs = {};
testTextAttrs(ID, 50, attrs, 50, 55);
testTextAttrs(ID, 50, attrs, defAttrs, 50, 55);
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign};
testTextAttrs(ID, 55, attrs, 55, 64);
testTextAttrs(ID, 55, attrs, defAttrs, 55, 64);
//////////////////////////////////////////////////////////////////////////
// area7
ID = "area7";
tempElem = document.getElementById(ID);
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
defAttrs = {
"language": "en",
"font-style": gComputedStyle.fontStyle,
"font-size": "12pt",
"background-color": "rgb(255, 255, 255)",
"font-weight": gComputedStyle.fontWeight,
"color": gComputedStyle.color,
"font-family": gComputedStyle.fontFamily,
"text-position": gComputedStyle.verticalAlign
};
testDefaultTextAttrs(ID, defAttrs);
attrs = {"language": "ru"};
testTextAttrs(ID, 0, attrs, defAttrs, 0, 12);
attrs = {};
testTextAttrs(ID, 12, attrs, defAttrs, 12, 13);
tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = { "background-color": gComputedStyle.backgroundColor};
testTextAttrs(ID, 13, attrs, defAttrs, 13, 26);
attrs = {};
testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
attrs = {"language": "de"};
testTextAttrs(ID, 27, attrs, defAttrs, 27, 42);
attrs = {};
testTextAttrs(ID, 42, attrs, defAttrs, 42, 50);
attrs = {};
testTextAttrs(ID, 43, attrs, defAttrs, 42, 50);
tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 50, attrs, defAttrs, 50, 57);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": gComputedStyle.fontWeight,
"color": gComputedStyle.color};
testTextAttrs(ID, 57, attrs, defAttrs, 57, 61);
tempElem = tempElem.parentNode;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 61, attrs, defAttrs, 61, 68);
//////////////////////////////////////////////////////////////////////////
// area9, different single style spans in styled paragraph
ID = "area9";
tempElem = document.getElementById(ID);
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
defAttrs = {
"font-style": gComputedStyle.fontStyle,
"font-size": "10pt",
"background-color": "rgb(255, 255, 255)",
"font-weight": gComputedStyle.fontWeight,
"color": gComputedStyle.color,
"font-family": gComputedStyle.fontFamily,
"text-position": gComputedStyle.verticalAlign
};
testDefaultTextAttrs(ID, defAttrs);
attrs = {};
testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
attrs = { "font-size": "12pt" };
testTextAttrs(ID, 7, attrs, defAttrs, 6, 12);
attrs = {};
testTextAttrs(ID, 13, attrs, defAttrs, 12, 21);
// Walk to the span with the different background color
tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = { "background-color": gComputedStyle.backgroundColor };
testTextAttrs(ID, 22, attrs, defAttrs, 21, 36);
attrs = {};
testTextAttrs(ID, 37, attrs, defAttrs, 36, 44);
// Walk from the background color span to the one with font-style
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = { "font-style": gComputedStyle.fontStyle };
testTextAttrs(ID, 45, attrs, defAttrs, 44, 61);
attrs = {};
testTextAttrs(ID, 62, attrs, defAttrs, 61, 69);
// Walk from span with font-style to the one with font-family.
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = { "font-family": gComputedStyle.fontFamily };
testTextAttrs(ID, 70, attrs, defAttrs, 69, 83);
attrs = {};
testTextAttrs(ID, 84, attrs, defAttrs, 83, 91);
attrs = { "text-underline-style": "solid" };
testTextAttrs(ID, 92, attrs, defAttrs, 91, 101);
attrs = {};
testTextAttrs(ID, 102, attrs, defAttrs, 101, 109);
attrs = { "text-line-through-style": "solid" };
testTextAttrs(ID, 110, attrs, defAttrs, 109, 122);
attrs = {};
testTextAttrs(ID, 123, attrs, defAttrs, 122, 130);
// area10, different single style spans in non-styled paragraph
ID = "area10";
tempElem = document.getElementById(ID);
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
defAttrs = {
"font-style": gComputedStyle.fontStyle,
"font-size": "12pt",
@ -321,45 +442,53 @@
testDefaultTextAttrs(ID, defAttrs);
attrs = {"language": "ru"};
testTextAttrs(ID, 0, attrs, 0, 12);
attrs = {};
testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
attrs = {"language": "en"};
testTextAttrs(ID, 12, attrs, 12, 13);
tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"language" :"en",
"background-color": gComputedStyle.backgroundColor};
testTextAttrs(ID, 13, attrs, 13, 26);
attrs = {"language": "en" };
testTextAttrs(ID, 26, attrs, 26, 27);
attrs = {"language": "de"};
testTextAttrs(ID, 27, attrs, 27, 42);
attrs = {"language": "en"};
testTextAttrs(ID, 42, attrs, 42, 43);
attrs = { "font-size": "14pt" };
testTextAttrs(ID, 7, attrs, defAttrs, 7, 13);
attrs = {};
testTextAttrs(ID, 43, attrs, 43, 50);
testTextAttrs(ID, 13, attrs, defAttrs, 13, 22);
tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
// Walk to the span with the different background color
tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 50, attrs, 50, 57);
attrs = { "background-color": gComputedStyle.backgroundColor };
testTextAttrs(ID, 23, attrs, defAttrs, 22, 37);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": gComputedStyle.fontWeight,
"color": gComputedStyle.color};
testTextAttrs(ID, 57, attrs, 57, 61);
attrs = {};
testTextAttrs(ID, 38, attrs, defAttrs, 37, 45);
tempElem = tempElem.parentNode;
// Walk from the background color span to the one with font-style
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
testTextAttrs(ID, 61, attrs, 61, 68);
attrs = {"font-style": gComputedStyle.fontStyle};
testTextAttrs(ID, 46, attrs, defAttrs, 45, 62);
attrs = {};
testTextAttrs(ID, 63, attrs, defAttrs, 62, 70);
// Walk from span with font-style to the one with font-family.
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-family": gComputedStyle.fontFamily};
testTextAttrs(ID, 71, attrs, defAttrs, 70, 84);
attrs = {};
testTextAttrs(ID, 85, attrs, defAttrs, 84, 92);
attrs = { "text-underline-style": "solid" };
testTextAttrs(ID, 93, attrs, defAttrs, 92, 102);
attrs = {};
testTextAttrs(ID, 103, attrs, defAttrs, 102, 110);
attrs = { "text-line-through-style": "solid" };
testTextAttrs(ID, 111, attrs, defAttrs, 110, 123);
attrs = {};
testTextAttrs(ID, 124, attrs, defAttrs, 123, 131);
//////////////////////////////////////////////////////////////////////////
// test spelling text attributes
@ -425,6 +554,22 @@
<input id="area8"/>
<p id="output"/>
<p id="area9" style="font-size: smaller">Small
<span style="font-size: 120%">bigger</span> smaller
<span style="background-color: blue;">background blue</span> normal
<span style="font-style: italic;">Different styling</span> normal
<span style="font-family: tahoma;">Different font</span> normal
<span style="text-decoration: underline;">underlined</span> normal
<span style="text-decoration: line-through;">strikethrough</span> normal
</p>
<p id="area10">Normal
<span style="font-size: 120%">bigger</span> smaller
<span style="background-color: blue;">background blue</span> normal
<span style="font-style: italic;">Different styling</span> normal
<span style="font-family: tahoma;">Different font</span> normal
<span style="text-decoration: underline;">underlined</span> normal
<span style="text-decoration: line-through;">strikethrough</span> normal
</p>
</body>
</html>