FocusCandidate::FocusCandidate(Node* node, FocusDirection direction) : visibleNode(0) , focusableNode(0) , enclosingScrollableBox(0) , distance(maxDistance()) , parentDistance(maxDistance()) , alignment(None) , parentAlignment(None) , isOffscreen(true) , isOffscreenAfterScrolling(true) { ASSERT(node); ASSERT(node->isElementNode()); if (node->hasTagName(HTMLNames::areaTag)) { HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); HTMLImageElement* image = area->imageElement(); if (!image || !image->renderer()) return; visibleNode = image; rect = virtualRectForAreaElementAndDirection(area, direction); } else { if (!node->renderer()) return; visibleNode = node; rect = nodeRectInAbsoluteCoordinates(node, true /* ignore border */); } focusableNode = node; isOffscreen = hasOffscreenRect(visibleNode); isOffscreenAfterScrolling = hasOffscreenRect(visibleNode, direction); }
// This method filters what element will get tap-highlight'ed or not. To start with, // we are going to highlight links (anchors with a valid href element), and elements // whose tap highlight color value is different than the default value. static Element* elementForTapHighlight(Element* elementUnderFatFinger) { // Do not bail out right way here if there element does not have a renderer. // It is the casefor <map> (descendent of <area>) elements. The associated <image> // element actually has the renderer. if (elementUnderFatFinger->renderer()) { Color tapHighlightColor = elementUnderFatFinger->renderStyle()->tapHighlightColor(); if (tapHighlightColor != RenderTheme::defaultTheme()->platformTapHighlightColor()) return elementUnderFatFinger; } bool isArea = elementUnderFatFinger->hasTagName(HTMLNames::areaTag); Node* linkNode = elementUnderFatFinger->enclosingLinkEventParentOrSelf(); if (!linkNode || !linkNode->isHTMLElement() || (!linkNode->renderer() && !isArea)) return 0; ASSERT(linkNode->isLink()); // FatFingers class selector ensure only anchor with valid href attr value get here. // It includes empty hrefs. Element* highlightCandidateElement = static_cast<Element*>(linkNode); if (!isArea) return highlightCandidateElement; HTMLAreaElement* area = static_cast<HTMLAreaElement*>(highlightCandidateElement); HTMLImageElement* image = area->imageElement(); if (image && image->renderer()) return image; return 0; }
LayoutRect virtualRectForAreaElementAndDirection(HTMLAreaElement& area, FocusType type) { ASSERT(area.imageElement()); // Area elements tend to overlap more than other focusable elements. We flatten the rect of the area elements // to minimize the effect of overlapping areas. LayoutRect rect = virtualRectForDirection(type, rectToAbsoluteCoordinates(area.document().frame(), area.computeRect(area.imageElement()->renderer())), 1); return rect; }
void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo) { Document* document = this->document(); if (document->printing() || !document->frame()->selection()->isFocusedAndActive()) return; if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints()) return; Element* focusedElement = document->focusedElement(); if (!focusedElement || !isHTMLAreaElement(focusedElement)) return; HTMLAreaElement* areaElement = toHTMLAreaElement(focusedElement); if (areaElement->imageElement() != node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't do it for // an area within an image, so we don't call RenderTheme::supportsFocusRing here. Path path = areaElement->computePath(this); if (path.isEmpty()) return; RenderStyle* areaElementStyle = areaElement->computedStyle(); unsigned short outlineWidth = areaElementStyle->outlineWidth(); if (!outlineWidth) return; // FIXME: Clip path instead of context when Skia pathops is ready. // https://crbug.com/251206 GraphicsContextStateSaver savedContext(*paintInfo.context); paintInfo.context->clip(absoluteContentBox()); paintInfo.context->drawFocusRing(path, outlineWidth, areaElementStyle->outlineOffset(), resolveColor(areaElementStyle, CSSPropertyOutlineColor)); }
void RenderImage::paintAreaElementFocusRing(PaintInfo& paintInfo) { Document* document = this->document(); if (document->printing() || !document->frame()->selection()->isFocusedAndActive()) return; if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints()) return; Node* focusedNode = document->focusedNode(); if (!focusedNode || !focusedNode->hasTagName(areaTag)) return; HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(focusedNode); if (areaElement->imageElement() != node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't do it for // an area within an image, so we don't call RenderTheme::supportsFocusRing here. Path path = areaElement->computePath(this); if (path.isEmpty()) return; // FIXME: Do we need additional code to clip the path to the image's bounding box? RenderStyle* areaElementStyle = areaElement->computedStyle(); unsigned short outlineWidth = areaElementStyle->outlineWidth(); if (!outlineWidth) return; paintInfo.context->drawFocusRing(path, outlineWidth, areaElementStyle->outlineOffset(), areaElementStyle->visitedDependentColor(CSSPropertyOutlineColor)); }
bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event) { Frame* curFrame = focusedOrMainFrame(); ASSERT(curFrame); Document* focusedDocument = curFrame->document(); if (!focusedDocument) return false; Node* focusedNode = focusedDocument->focusedNode(); Node* container = focusedDocument; if (container->isDocumentNode()) static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); // Figure out the starting rect. LayoutRect startingRect; if (focusedNode) { if (!hasOffscreenRect(focusedNode)) { container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode); startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */); } else if (focusedNode->hasTagName(areaTag)) { HTMLAreaElement* area = static_cast<HTMLAreaElement*>(focusedNode); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area->imageElement()); startingRect = virtualRectForAreaElementAndDirection(area, direction); } } bool consumed = false; do { consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event); startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */); container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container); if (container && container->isDocumentNode()) static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets(); } while (!consumed && container); return consumed; }
void RenderImage::readyWRATHWidgetAreaElementFocusRing(PaintedWidgetsOfWRATHHandle& handle, PaintInfoOfWRATH& paintInfo) { RenderImage_ReadyWRATHWidgetAreaElementFocusRing *d(RenderImage_ReadyWRATHWidgetAreaElementFocusRing::object(this, handle)); ContextOfWRATH::AutoPushNode autoPushRoot(paintInfo.wrath_context, d->m_root_node); if (d->m_focus_ring.widget()) d->m_focus_ring.widget()->visible(false); Document* document = this->document(); if (document->printing() || !document->frame()->selection()->isFocusedAndActive()) return; /* if (paintInfo.context->paintingDisabled() && !paintInfo.context->updatingControlTints()) return; */ Node* focusedNode = document->focusedNode(); if (!focusedNode || !focusedNode->hasTagName(areaTag)) return; HTMLAreaElement* areaElement = static_cast<HTMLAreaElement*>(focusedNode); if (areaElement->imageElement() != node()) return; // Even if the theme handles focus ring drawing for entire elements, it won't do it for // an area within an image, so we don't call RenderTheme::supportsFocusRing here. Path path = areaElement->computePath(this); if (path.isEmpty()) return; // FIXME: Do we need additional code to clip the path to the image's bounding box? RenderStyle* areaElementStyle = areaElement->computedStyle(); unsigned short outlineWidth = areaElementStyle->outlineWidth(); if (!outlineWidth) return; if (!d->m_focus_ring_shape || d->m_focus_ring_dirty) { if (!d->m_focus_ring_shape) { d->m_focus_ring_shape = WRATHNew WRATHShapeF; } d->m_focus_ring_shape->clear(); d->m_focus_ring_shape->new_outline(); QPainterPath qpath = path.platformPath(); // Skip the first element, it is not needed because it's the same as the last for (int i = 1; i < qpath.elementCount(); ++i) { const QPainterPath::Element & cur = qpath.elementAt(i); switch (cur.type) { case QPainterPath::MoveToElement: { ASSERT_NOT_REACHED(); break; } case QPainterPath::LineToElement: { QPointF p(cur); d->m_focus_ring_shape->current_outline() << vec2(p.x(), p.y()); break; } case QPainterPath::CurveToElement: { QPainterPath::Element c1 = qpath.elementAt(i+1); QPainterPath::Element c2 = qpath.elementAt(i+2); ASSERT(c1.type == QPainterPath::CurveToDataElement); ASSERT(c2.type == QPainterPath::CurveToDataElement); QPointF p1(cur); QPointF p2(c1); QPointF p3(c2); d->m_focus_ring_shape->current_outline() << WRATHOutlineF::control_point(vec2(p1.x(), p1.y())) << WRATHOutlineF::control_point(vec2(p2.x(), p2.y())) << vec2(p3.x(), p3.y()); i += 2; break; } case QPainterPath::CurveToDataElement: { ASSERT_NOT_REACHED(); break; } } } } vec4 c; Color wc = areaElementStyle->visitedDependentColor(CSSPropertyOutlineColor); wc.getRGBA(c.x(), c.y(), c.z(), c.w()); paintInfo.wrath_context->add_stroked_shape(d->m_focus_ring, WRATHWidgetGenerator::ColorProperties(c), WRATHWidgetGenerator::shape_value(*d->m_focus_ring_shape), WRATHWidgetGenerator::StrokingParameters() .close_outline(true) .width(outlineWidth) .stroke_curves(WRATHWidgetGenerator::dashed_stroke)); d->m_focus_ring.widget()->visible(true); }