bool nsAccUtils::IsTextInterfaceSupportCorrect(Accessible* aAccessible) { // Don't test for accessible docs, it makes us create accessibles too // early and fire mutation events before we need to if (aAccessible->IsDoc()) return true; bool foundText = false; uint32_t childCount = aAccessible->ChildCount(); for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { Accessible* child = aAccessible->GetChildAt(childIdx); if (child->IsText()) { foundText = true; break; } } return !foundText || aAccessible->IsHyperText(); }
void TextAttrsMgr::GetAttributes(nsIPersistentProperties* aAttributes, uint32_t* aStartOffset, uint32_t* aEndOffset) { // 1. Hyper text accessible must be specified always. // 2. Offset accessible and result hyper text offsets must be specified in // the case of text attributes. // 3. Offset accessible and result hyper text offsets must not be specified // but include default text attributes flag and attributes list must be // specified in the case of default text attributes. NS_PRECONDITION(mHyperTextAcc && ((mOffsetAcc && mOffsetAccIdx != -1 && aStartOffset && aEndOffset) || (!mOffsetAcc && mOffsetAccIdx == -1 && !aStartOffset && !aEndOffset && mIncludeDefAttrs && aAttributes)), "Wrong usage of TextAttrsMgr!"); // Embedded objects are combined into own range with empty attributes set. if (mOffsetAcc && !mOffsetAcc->IsText()) { for (int32_t childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) { Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx); if (currAcc->IsText()) break; (*aStartOffset)--; } uint32_t childCount = mHyperTextAcc->ChildCount(); for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childCount; childIdx++) { Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx); if (currAcc->IsText()) break; (*aEndOffset)++; } return; } // Get the content and frame of the accessible. In the case of document // accessible it's role content and root frame. nsIContent* hyperTextElm = mHyperTextAcc->GetContent(); if (!hyperTextElm) return; // XXX: we don't support text attrs on document with no body nsIFrame* rootFrame = mHyperTextAcc->GetFrame(); MOZ_ASSERT(rootFrame, "No frame for accessible!"); if (!rootFrame) return; nsIContent *offsetNode = nullptr, *offsetElm = nullptr; nsIFrame *frame = nullptr; if (mOffsetAcc) { offsetNode = mOffsetAcc->GetContent(); offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode); MOZ_ASSERT(offsetElm, "No element for offset accessible!"); if (!offsetElm) return; frame = offsetElm->GetPrimaryFrame(); } // "language" text attribute LangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode); // "aria-invalid" text attribute InvalidTextAttr invalidTextAttr(hyperTextElm, offsetNode); // "background-color" text attribute BGColorTextAttr bgColorTextAttr(rootFrame, frame); // "color" text attribute ColorTextAttr colorTextAttr(rootFrame, frame); // "font-family" text attribute FontFamilyTextAttr fontFamilyTextAttr(rootFrame, frame); // "font-size" text attribute FontSizeTextAttr fontSizeTextAttr(rootFrame, frame); // "font-style" text attribute FontStyleTextAttr fontStyleTextAttr(rootFrame, frame); // "font-weight" text attribute FontWeightTextAttr fontWeightTextAttr(rootFrame, frame); // "auto-generated" text attribute AutoGeneratedTextAttr autoGenTextAttr(mHyperTextAcc, mOffsetAcc); // "text-underline(line-through)-style(color)" text attributes TextDecorTextAttr textDecorTextAttr(rootFrame, frame); // "text-position" text attribute TextPosTextAttr textPosTextAttr(rootFrame, frame); TextAttr* attrArray[] = { &langTextAttr, &invalidTextAttr, &bgColorTextAttr, &colorTextAttr, &fontFamilyTextAttr, &fontSizeTextAttr, &fontStyleTextAttr, &fontWeightTextAttr, &autoGenTextAttr, &textDecorTextAttr, &textPosTextAttr }; // Expose text attributes if applicable. if (aAttributes) { for (uint32_t idx = 0; idx < ArrayLength(attrArray); idx++) attrArray[idx]->Expose(aAttributes, mIncludeDefAttrs); } // Expose text attributes range where they are applied if applicable. if (mOffsetAcc) GetRange(attrArray, ArrayLength(attrArray), aStartOffset, aEndOffset); }
NS_IMETHODIMP nsAccessiblePivot::MovePreviousByText(TextBoundaryType aBoundary, bool aIsFromUserInput, uint8_t aArgc, bool* aResult) { NS_ENSURE_ARG(aResult); *aResult = false; int32_t tempStart = mStartOffset, tempEnd = mEndOffset; Accessible* tempPosition = mPosition; Accessible* root = GetActiveRoot(); while (true) { Accessible* curPosition = tempPosition; HyperTextAccessible* text; // Find the nearest text node using a reverse preorder traversal starting // from the current node. if (!(text = tempPosition->AsHyperText())) { text = SearchForText(tempPosition, true); if (!text) return NS_OK; if (text != curPosition) tempStart = tempEnd = -1; tempPosition = text; } // If the search led to the parent of the node we started on (e.g. when // starting on a text leaf), start the text movement from the end of that // node, otherwise we just default to 0. if (tempStart == -1) { if (tempPosition != curPosition) tempStart = text == curPosition->Parent() ? text->GetChildOffset(curPosition) : text->CharacterCount(); else tempStart = 0; } // If there's no more text on the current node, try to find the previous // text node; if there isn't one, bail out. if (tempStart == 0) { if (tempPosition == root) return NS_OK; // If we're currently sitting on a link, try move to either the previous // sibling or the parent, whichever is closer to the current end // offset. Otherwise, do a forward search for the next node to land on // (we don't do this in the first case because we don't want to go to the // subtree). Accessible* sibling = tempPosition->PrevSibling(); if (tempPosition->IsLink()) { if (sibling && sibling->IsLink()) { HyperTextAccessible* siblingText = sibling->AsHyperText(); tempStart = tempEnd = siblingText ? siblingText->CharacterCount() : -1; tempPosition = sibling; } else { tempStart = tempPosition->StartOffset(); tempEnd = tempPosition->EndOffset(); tempPosition = tempPosition->Parent(); } } else { HyperTextAccessible* tempText = SearchForText(tempPosition, true); if (!tempText) return NS_OK; tempPosition = tempText; tempStart = tempEnd = tempText->CharacterCount(); } continue; } AccessibleTextBoundary startBoundary, endBoundary; switch (aBoundary) { case CHAR_BOUNDARY: startBoundary = nsIAccessibleText::BOUNDARY_CHAR; endBoundary = nsIAccessibleText::BOUNDARY_CHAR; break; case WORD_BOUNDARY: startBoundary = nsIAccessibleText::BOUNDARY_WORD_START; endBoundary = nsIAccessibleText::BOUNDARY_WORD_END; break; default: return NS_ERROR_INVALID_ARG; } nsAutoString unusedText; int32_t newStart = 0, newEnd = 0, currentStart = tempStart, potentialEnd = 0; text->TextBeforeOffset(tempStart, startBoundary, &newStart, &newEnd, unusedText); if (newStart < tempStart) tempStart = newEnd >= currentStart ? newStart : newEnd; else // XXX: In certain odd cases newStart is equal to tempStart text->TextBeforeOffset(tempStart - 1, startBoundary, &newStart, &tempStart, unusedText); text->TextAtOffset(tempStart, endBoundary, &newStart, &potentialEnd, unusedText); tempEnd = potentialEnd < tempEnd ? potentialEnd : currentStart; // The offset range we've obtained might have embedded characters in it, // limit the range to the start of the last occurrence of an embedded // character. Accessible* childAtOffset = nullptr; for (int32_t i = tempEnd - 1; i >= tempStart; i--) { childAtOffset = text->GetChildAtOffset(i); if (childAtOffset && !childAtOffset->IsText()) { tempStart = childAtOffset->EndOffset(); break; } } // If there's an embedded character at the very end of the range, we // instead want to traverse into it. So restart the movement with // the child as the starting point. if (childAtOffset && !childAtOffset->IsText() && tempEnd == static_cast<int32_t>(childAtOffset->EndOffset())) { tempPosition = childAtOffset; tempStart = tempEnd = childAtOffset->AsHyperText()->CharacterCount(); continue; } *aResult = true; Accessible* startPosition = mPosition; int32_t oldStart = mStartOffset, oldEnd = mEndOffset; mPosition = tempPosition; mStartOffset = tempStart; mEndOffset = tempEnd; NotifyOfPivotChange(startPosition, oldStart, oldEnd, nsIAccessiblePivot::REASON_TEXT, (aArgc > 0) ? aIsFromUserInput : true); return NS_OK; } }