📄 accessibilityobjectwrapper.mm
字号:
static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range){ RenderStyle* style = renderer->style(); // set basic font info AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range); // set basic colors AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range); AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range); // set super/sub scripting EVerticalAlign alignment = style->verticalAlign(); if (alignment == SUB) AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range); else if (alignment == SUPER) AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range); else [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range]; // set shadow if (style->textShadow()) AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range); else [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range]; // set underline and strikethrough int decor = style->textDecorationsInEffect(); if ((decor & UNDERLINE) == 0) { [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range]; [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range]; } if ((decor & LINE_THROUGH) == 0) { [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range]; [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range]; } if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) { // find colors using quirk mode approach (strict mode would use current // color for all but the root line box, which would use getTextDecorationColors) Color underline, overline, linethrough; renderer->getTextDecorationColors(decor, underline, overline, linethrough); if ((decor & UNDERLINE) != 0) { AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range); AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range); } if ((decor & LINE_THROUGH) != 0) { AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range); AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range); } }}static int blockquoteLevel(RenderObject* renderer){ if (!renderer) return 0; int result = 0; for (Node* node = renderer->node(); node; node = node->parent()) { if (node->hasTagName(blockquoteTag)) result += 1; } return result;}static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range){ int quoteLevel = blockquoteLevel(renderer); if (quoteLevel) [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range]; else [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];}static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range){ Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node); Vector<DocumentMarker>::iterator markerIt = markers.begin(); unsigned endOffset = (unsigned)offset + range.length; for ( ; markerIt != markers.end(); markerIt++) { DocumentMarker marker = *markerIt; if (marker.type != DocumentMarker::Spelling) continue; if (marker.endOffset <= (unsigned)offset) continue; if (marker.startOffset > endOffset) break; // add misspelling attribute for the intersection of the marker and the range int rStart = range.location + (marker.startOffset - offset); int rLength = MIN(marker.endOffset, endOffset) - marker.startOffset; NSRange spellRange = NSMakeRange(rStart, rLength); AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange); if (marker.endOffset > endOffset + 1) break; }}static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range){ int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->node()); if (parentHeadingLevel) [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range]; else [attrString removeAttribute:@"AXHeadingLevel" range:range];}static AccessibilityObject* AXLinkElementForNode(Node* node){ RenderObject* obj = node->renderer(); if (!obj) return 0; RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->getOrCreate(obj); Element* anchor = axObj->anchorElement(); if (!anchor) return 0; RenderObject* anchorRenderer = anchor->renderer(); if (!anchorRenderer) return 0; return anchorRenderer->document()->axObjectCache()->getOrCreate(anchorRenderer);}static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range){ if (object && object->isAccessibilityRenderObject()) { // make a serialiazable AX object RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer(); if (!renderer) return; Document* doc = renderer->document(); if (!doc) return; AXObjectCache* cache = doc->axObjectCache(); if (!cache) return; AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()]; if (axElement) { [attrString addAttribute:attribute value:(id)axElement range:range]; CFRelease(axElement); } } else [attrString removeAttribute:attribute range:range];}static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length){ // skip invisible text if (!node->renderer()) return; // easier to calculate the range before appending the string NSRange attrStringRange = NSMakeRange([attrString length], length); // append the string from this node [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]]; // add new attributes and remove irrelevant inherited ones // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually. // remove inherited attachment from prior AXAttributedStringAppendReplaced [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange]; // set new attributes AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange); AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange); AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange); AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AXLinkElementForNode(node), attrStringRange); // do spelling last because it tends to break up the range AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange);}static NSString* nsStringForReplacedNode(Node* replacedNode){ // we should always be given a rendered node and a replaced node, but be safe // replaced nodes are either attachments (widgets) or images if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) { ASSERT_NOT_REACHED(); return nil; } // create an AX object, but skip it if it is not supposed to be seen RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); if (obj->accessibilityIsIgnored()) return nil; // use the attachmentCharacter to represent the replaced node const UniChar attachmentChar = NSAttachmentCharacter; return [NSString stringWithCharacters:&attachmentChar length:1];}- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange{ // extract the start and end VisiblePosition VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange); if (startVisiblePosition.isNull()) return nil; VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(textMarkerRange); if (endVisiblePosition.isNull()) return nil; // iterate over the range to build the AX attributed string NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init]; TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get()); while (!it.atEnd()) { // locate the node and starting offset for this range int exception = 0; Node* node = it.range()->startContainer(exception); ASSERT(node == it.range()->endContainer(exception)); int offset = it.range()->startOffset(exception); // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) if (it.length() != 0) { AXAttributedStringAppendText(attrString, node, offset, it.characters(), it.length()); } else { Node* replacedNode = node->childNode(offset); NSString *attachmentString = nsStringForReplacedNode(replacedNode); if (attachmentString) { NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]); // append the placeholder string [[attrString mutableString] appendString:attachmentString]; // remove all inherited attributes [attrString setAttributes:nil range:attrStringRange]; // add the attachment attribute AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange); } } it.advance(); } return [attrString autorelease];}static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePosition startPosition, VisiblePosition endPosition){ WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(startPosition); WebCoreTextMarker* endTextMarker = textMarkerForVisiblePosition(endPosition); return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);}- (NSArray*)accessibilityActionNames{ if (!m_object) return nil; m_object->updateBackingStore(); static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil]; static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil]; static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil]; NSArray *actions; if (m_object->actionElement()) actions = actionElementActions; else if (m_object->isMenuRelated()) actions = menuElementActions; else if (m_object->isAttachment()) actions = [[self attachmentView] accessibilityActionNames]; else actions = defaultElementActions; return actions;}- (NSArray*)accessibilityAttributeNames{ if (!m_object) return nil; m_object->updateBackingStore(); if (m_object->isAttachment()) return [[self attachmentView] accessibilityAttributeNames]; static NSArray* attributes = nil; static NSArray* anchorAttrs = nil; static NSArray* webAreaAttrs = nil; static NSArray* textAttrs = nil; static NSArray* listBoxAttrs = nil; static NSArray* rangeAttrs = nil; static NSArray* commonMenuAttrs = nil; static NSArray* menuAttrs = nil; static NSArray* menuBarAttrs = nil; static NSArray* menuItemAttrs = nil; static NSArray* menuButtonAttrs = nil; static NSArray* controlAttrs = nil; static NSArray* tableAttrs = nil; static NSArray* tableRowAttrs = nil; static NSArray* tableColAttrs = nil; static NSArray* tableCellAttrs = nil;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -