static Node* findLastFocusableNode(Frame* frame, const IntRect* specificRect) { #if PLATFORM(WKC) CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT); #endif Node* node = frame->document()->lastChild(); while (node) { if (!isNodeInSpecificRect(node, specificRect)) { node = node->traversePreviousNodePostOrder(); continue; } if (node->isFrameOwnerElement()) { HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); if (owner->contentFrame()) { node = findLastFocusableNode(owner->contentFrame(), specificRect); if (node) break; node = owner; } } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) { node = node->lastChild(); } if (node->isFocusable() && !node->isFrameOwnerElement()) { break; } node = node->traversePreviousNodePostOrder(); } if (node) { return node->isFocusable() ? node : 0; } return 0; }
bool InspectorBackend::addSourceToFrame(const String& mimeType, const String& source, Node* frameNode) { ASSERT_ARG(frameNode, frameNode); if (!frameNode) return false; if (!frameNode->attached()) { ASSERT_NOT_REACHED(); return false; } ASSERT(frameNode->isElementNode()); if (!frameNode->isElementNode()) return false; Element* element = static_cast<Element*>(frameNode); ASSERT(element->isFrameOwnerElement()); if (!element->isFrameOwnerElement()) return false; HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element); ASSERT(frameOwner->contentFrame()); if (!frameOwner->contentFrame()) return false; FrameLoader* loader = frameOwner->contentFrame()->loader(); loader->setResponseMIMEType(mimeType); loader->begin(); loader->write(source); loader->end(); return true; }
// intersectingRegions and remainingFingerRegion are all in main frame contents coordinates, // even on recursive calls of ::findIntersectingRegions. bool FatFingers::findIntersectingRegions(Document* document, Vector<IntersectingRegion>& intersectingRegions, Platform::IntRectRegion& remainingFingerRegion) { if (!document || !document->frame()->view()) return false; // The layout needs to be up-to-date to determine if a node is focusable. document->updateLayoutIgnorePendingStylesheets(); // Create fingerRect. IntPoint frameContentPos(document->frame()->view()->windowToContents(m_webPage->m_mainFrame->view()->contentsToWindow(m_contentPos))); #if DEBUG_FAT_FINGERS IntRect fingerRect(fingerRectForPoint(frameContentPos)); IntRect screenFingerRect = m_webPage->mapToTransformed(fingerRect); log(LogLevelInfo, "fat finger rect now %d, %d, %d, %d", screenFingerRect.x(), screenFingerRect.y(), screenFingerRect.width(), screenFingerRect.height()); // only record the first finger rect if (document == m_webPage->m_mainFrame->document()) m_debugFatFingerRect = m_webPage->mapToTransformed(m_webPage->mapFromContentsToViewport(fingerRect)); #endif bool foundOne = false; RenderLayer* lowestPositionedEnclosingLayerSoFar = 0; // Iterate over the list of nodes (and subrects of nodes where possible), for each saving the // intersection of the bounding box with the finger rect. ListHashSet<RefPtr<Node> > intersectedNodes; getNodesFromRect(document, frameContentPos, intersectedNodes); ListHashSet<RefPtr<Node> >::const_iterator it = intersectedNodes.begin(); ListHashSet<RefPtr<Node> >::const_iterator end = intersectedNodes.end(); for ( ; it != end; ++it) { Node* curNode = (*it).get(); if (!curNode || !curNode->renderer()) continue; if (remainingFingerRegion.isEmpty()) break; bool isElement = curNode->isElementNode(); if (isElement && isValidFrameOwner(toElement(curNode))) { HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(curNode); Document* childDocument = owner && owner->contentFrame() ? owner->contentFrame()->document() : 0; if (!childDocument) continue; ASSERT(childDocument->frame()->view()); foundOne |= findIntersectingRegions(childDocument, intersectingRegions, remainingFingerRegion); } else if (isElement && m_targetType == ClickableElement) { foundOne |= checkForClickableElement(toElement(curNode), intersectingRegions, remainingFingerRegion, lowestPositionedEnclosingLayerSoFar); } else if (m_targetType == Text) foundOne |= checkForText(curNode, intersectingRegions, remainingFingerRegion); } return foundOne; }
Node* FocusController::deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event) { // The node we found might be a HTMLFrameOwnerElement or a shadow host, so descend down the tree until we find either: // 1) a focusable node, or // 2) the deepest-nested HTMLFrameOwnerElement or shadow host. while (isTreeScopeOwner(node)) { Node* foundNode; if (node->isFrameOwnerElement()) { HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); if (!owner->contentFrame()) break; Document* document = owner->contentFrame()->document(); foundNode = findFocusableNode(direction, document, 0, event); } else { ASSERT(shadowRoot(node)); // FIXME: Some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in their focus() methods. // Skipping these elements is the safest fix until we find a better way. if (node->hasTagName(inputTag) || node->hasTagName(textareaTag)) break; foundNode = findFocusableNode(direction, shadowRoot(node), 0, event); } if (!foundNode) break; ASSERT(node != foundNode); node = foundNode; } return node; }
void FocusController::deepFindFocusableNodeInDirection(Node* focusedNode, Node* candidate, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closestFocusCandidate) { HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(candidate); if (!owner->contentFrame()) return; Document* innerDocument = owner->contentFrame()->document(); if (!innerDocument) return; if (innerDocument == focusedNode->document()) findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, closestFocusCandidate); else { // Check if the current {i}frame element itself is a good candidate // to move focus to. If it is, then we traverse its inner nodes. // Lets pass a copy of the best candidate, to not get fooled by a // frame without focusable elements. FocusCandidate focusCandidateCopy = closestFocusCandidate; long long distance = distanceInDirection(focusedNode, candidate, direction, focusCandidateCopy); if (distance < focusCandidateCopy.distance) { focusCandidateCopy.parentAlignment = focusCandidateCopy.alignment; focusCandidateCopy.parentDistance = distance; findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, focusCandidateCopy); // If we really have an inner closer focus candidate node, take it. if (closestFocusCandidate.node != focusCandidateCopy.node) closestFocusCandidate = focusCandidateCopy; } } }
void FocusController::findHorizontallyFocusableNodeInRect(FocusDirection direction, Node* start, KeyboardEvent* event, const IntRect* rect, Node** candidateNode, IntRect& candidateNodeRect) { #if PLATFORM(WKC) CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT); #endif // ASSERT(direction == FocusDirectionLeft || direction == FocusDirectionRight); if (!start) return ; Node* node = start; HTMLFrameOwnerElement* owner; Document* document; IntRect nodeRect; while (node) { if (!isNodeInSpecificRect(node, rect)) { node = getClosestNode(node, direction); continue; } owner = 0; if (node->isFrameOwnerElement()) { owner = static_cast<HTMLFrameOwnerElement*>(node); if (!owner->contentFrame()) { *candidateNode = 0; return; } document = owner->contentFrame()->document(); findHorizontallyFocusableNodeInRect(direction, document, event, rect, candidateNode, candidateNodeRect); } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) { findHorizontallyFocusableNodeInRect(direction, node->firstChild(), event, rect, candidateNode, candidateNodeRect); } else { if (node->isFocusable() && !node->isFrameOwnerElement()) { nodeRect = node->renderer()->absoluteBoundingBoxRect(); FrameView* frameView = node->document()->view(); if (!frameView) { *candidateNode = 0; return; } nodeRect = frameView->contentsToWindow(nodeRect); nodeRect.intersect(*rect); if (!nodeRect.isEmpty()) { if (candidateNodeRect.isEmpty()) { *candidateNode = node; candidateNodeRect = nodeRect; } if (direction == FocusDirectionRight && candidateNodeRect.x() > nodeRect.x()) { *candidateNode = node; candidateNodeRect = nodeRect; } else if (direction == FocusDirectionLeft && candidateNodeRect.x() < nodeRect.x()) { *candidateNode = node; candidateNodeRect = nodeRect; } } } } node = getClosestNode(node, direction); } }
void FocusController::deepFindFocusableNodeInDirection(Node* container, Node* focusedNode, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest) { ASSERT(container->hasTagName(frameTag) || container->hasTagName(iframeTag) || isScrollableContainerNode(container)); // Track if focusedNode is a descendant of the current container node being processed. bool descendantOfContainer = false; Node* firstChild = 0; // Iframe or Frame. if (container->hasTagName(frameTag) || container->hasTagName(iframeTag)) { HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(container); if (!owner->contentFrame()) return; Document* innerDocument = owner->contentFrame()->document(); if (!innerDocument) return; descendantOfContainer = isNodeDeepDescendantOfDocument(focusedNode, innerDocument); firstChild = innerDocument->firstChild(); // Scrollable block elements (e.g. <div>, etc) } else if (isScrollableContainerNode(container)) { firstChild = container->firstChild(); descendantOfContainer = focusedNode->isDescendantOf(container); } if (descendantOfContainer) { findFocusableNodeInDirection(firstChild, focusedNode, direction, event, closest); return; } // Check if the current container element itself is a good candidate // to move focus to. If it is, then we traverse its inner nodes. FocusCandidate candidateParent = FocusCandidate(container); distanceDataForNode(direction, focusedNode, candidateParent); // Bail out if distance is maximum. if (candidateParent.distance == maxDistance()) return; // FIXME: Consider alignment? if (candidateParent.distance < closest.distance) findFocusableNodeInDirection(firstChild, focusedNode, direction, event, closest, candidateParent); }
void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent, ScrollbarMode horizontalScrollbarMode, bool horizontalLock, ScrollbarMode verticalScrollbarMode, bool verticalLock) { ASSERT(this); ASSERT(page()); bool isLocalRoot = this->isLocalRoot(); if (isLocalRoot && view()) view()->setParentVisible(false); setView(nullptr); FrameView* frameView = nullptr; if (isLocalRoot) { frameView = FrameView::create(this, viewportSize); // The layout size is set by WebViewImpl to support @viewport frameView->setLayoutSizeFixedToFrameSize(false); } else { frameView = FrameView::create(this); } frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock); setView(frameView); frameView->updateBackgroundRecursively(backgroundColor, transparent); if (isLocalRoot) frameView->setParentVisible(true); // FIXME: Not clear what the right thing for OOPI is here. if (!ownerLayoutItem().isNull()) { HTMLFrameOwnerElement* owner = deprecatedLocalOwner(); ASSERT(owner); // FIXME: OOPI might lead to us temporarily lying to a frame and telling it // that it's owned by a FrameOwner that knows nothing about it. If we're // lying to this frame, don't let it clobber the existing widget. if (owner->contentFrame() == this) owner->setWidget(frameView); } if (owner()) view()->setCanHaveScrollbars(owner()->scrollingMode() != ScrollbarAlwaysOff); }
static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event) { // The node we found might be a HTMLFrameOwnerElement, so descend down the frame tree until we find either: // 1) a focusable node, or // 2) the deepest-nested HTMLFrameOwnerElement while (node && node->isFrameOwnerElement()) { HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); if (!owner->contentFrame()) break; Document* document = owner->contentFrame()->document(); node = (direction == FocusDirectionForward) ? document->nextFocusableNode(0, event) : document->previousFocusableNode(0, event); if (!node) { node = owner; break; } } return node; }
bool LayoutPart::requiresAcceleratedCompositing() const { // There are two general cases in which we can return true. First, if this is a plugin // LayoutObject and the plugin has a layer, then we need a layer. Second, if this is // a LayoutObject with a contentDocument and that document needs a layer, then we need // a layer. if (widget() && widget()->isPluginView() && toPluginView(widget())->platformLayer()) return true; if (!node() || !node()->isFrameOwnerElement()) return false; HTMLFrameOwnerElement* element = toHTMLFrameOwnerElement(node()); if (element->contentFrame() && element->contentFrame()->isRemoteFrame()) return true; if (Document* contentDocument = element->contentDocument()) { if (LayoutView* view = contentDocument->layoutView()) return view->usesCompositing(); } return false; }
Node* FocusController::findFocusableNodeDecendingDownIntoFrameDocument(FocusDirection direction, Node* node, KeyboardEvent* event) { // The node we found might be a HTMLFrameOwnerElement, so descend down the tree until we find either: // 1) a focusable node, or // 2) the deepest-nested HTMLFrameOwnerElement. while (node && node->isFrameOwnerElement()) { HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); if (!owner->contentFrame()) break; Node* foundNode = findFocusableNode(direction, FocusNavigationScope::focusNavigationScopeOwnedByIFrame(owner), 0, event); if (!foundNode) break; ASSERT(node != foundNode); node = foundNode; } return node; }
void SerializerMarkupAccumulator::appendCustomAttributes(StringBuilder& out, Element* element, Namespaces* namespaces) { if (!element->isFrameOwnerElement()) return; HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element); Frame* frame = frameOwner->contentFrame(); if (!frame) return; KURL url = frame->document()->url(); if (url.isValid() && !url.protocolIs("about")) return; // We need to give a fake location to blank frames so they can be referenced by the serialized frame. url = m_serializer->urlForBlankFrame(frame); appendAttribute(out, element, Attribute(frameOwnerURLAttributeName(*frameOwner), url.string()), namespaces); }
Node* FocusController::findVerticallyFocusableNodeInRect(FocusDirection direction, Node* start, KeyboardEvent* event, const IntRect* rect) { #if PLATFORM(WKC) CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT); #endif ASSERT(direction == FocusDirectionUp || direction == FocusDirectionDown); if (!start) return 0; Node* node = start; HTMLFrameOwnerElement* owner; Document* document; while (node) { if (!isNodeInSpecificRect(node, rect)) { node = getClosestNode(node, direction); continue; } owner = 0; if (node->isFrameOwnerElement()) { owner = static_cast<HTMLFrameOwnerElement*>(node); if (!owner->contentFrame()) { node = 0; break; } document = owner->contentFrame()->document(); if (direction == FocusDirectionUp) { node = findVerticallyFocusableNodeInRect(direction, document->lastChild(), event, rect); } else { node = findVerticallyFocusableNodeInRect(direction, document->firstChild(), event, rect); } if (node) break; node = getClosestNode(owner, direction); continue; } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) { Node* childNode = 0; if (direction == FocusDirectionUp) { childNode = findVerticallyFocusableNodeInRect(direction, node->lastChild(), event, rect); } else { ASSERT(direction == FocusDirectionDown); childNode = findVerticallyFocusableNodeInRect(direction, node->firstChild(), event, rect); } if (!childNode) { node = getClosestNode(node, direction, true); if (!node) break; } else { node = childNode; break; } } if (node->isFocusable() && !node->isFrameOwnerElement()) { break; } if (owner) { node = owner; } node = getClosestNode(node, direction); } return node; }
bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus) { Frame* frame = focusedOrMainFrame(); ASSERT(frame); Document* document = frame->document(); Node* currentNode = document->focusedNode(); // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled(); if (caretBrowsing && !currentNode) currentNode = frame->selection()->start().deprecatedNode(); document->updateLayoutIgnorePendingStylesheets(); RefPtr<Node> node = findFocusableNodeAcrossFocusScope(direction, FocusNavigationScope::focusNavigationScopeOf(currentNode ? currentNode : document), currentNode, event); if (!node) { // We didn't find a node to focus, so we should try to pass focus to Chrome. if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) { document->setFocusedNode(0); setFocusedFrame(0); m_page->chrome()->takeFocus(direction); return true; } // Chrome doesn't want focus, so we should wrap focus. node = findFocusableNodeRecursively(direction, FocusNavigationScope::focusNavigationScopeOf(m_page->mainFrame()->document()), 0, event); node = findFocusableNodeDecendingDownIntoFrameDocument(direction, node.get(), event); if (!node) return false; } ASSERT(node); if (node == document->focusedNode()) // Focus wrapped around to the same node. return true; if (!node->isElementNode()) // FIXME: May need a way to focus a document here. return false; if (node->isFrameOwnerElement() && (!node->isPluginElement() || !node->isKeyboardFocusable(event))) { // We focus frames rather than frame owners. // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user. HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node.get()); if (!owner->contentFrame()) return false; document->setFocusedNode(0); setFocusedFrame(owner->contentFrame()); return true; } // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in // their focus() methods. Document* newDocument = node->document(); if (newDocument != document) // Focus is going away from this document, so clear the focused node. document->setFocusedNode(0); if (newDocument) setFocusedFrame(newDocument->frame()); if (caretBrowsing) { Position position = firstPositionInOrBeforeNode(node.get()); VisibleSelection newSelection(position, position, DOWNSTREAM); if (frame->selection()->shouldChangeSelection(newSelection)) frame->selection()->setSelection(newSelection); } static_cast<Element*>(node.get())->focus(false); return true; }
bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus) { Frame* frame = focusedOrMainFrame(); ASSERT(frame); Document* document = frame->document(); Node* currentNode = document->focusedNode(); // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself bool caretBrowsing = focusedOrMainFrame()->settings()->caretBrowsingEnabled(); if (caretBrowsing && !currentNode) currentNode = frame->selection()->start().node(); document->updateLayoutIgnorePendingStylesheets(); Node* node = (direction == FocusDirectionForward) ? document->nextFocusableNode(currentNode, event) : document->previousFocusableNode(currentNode, event); // If there's no focusable node to advance to, move up the frame tree until we find one. while (!node && frame) { Frame* parentFrame = frame->tree()->parent(); if (!parentFrame) break; Document* parentDocument = parentFrame->document(); HTMLFrameOwnerElement* owner = frame->ownerElement(); if (!owner) break; node = (direction == FocusDirectionForward) ? parentDocument->nextFocusableNode(owner, event) : parentDocument->previousFocusableNode(owner, event); frame = parentFrame; } node = deepFocusableNode(direction, node, event); if (!node) { // We didn't find a node to focus, so we should try to pass focus to Chrome. if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) { document->setFocusedNode(0); setFocusedFrame(0); m_page->chrome()->takeFocus(direction); return true; } // Chrome doesn't want focus, so we should wrap focus. Document* d = m_page->mainFrame()->document(); node = (direction == FocusDirectionForward) ? d->nextFocusableNode(0, event) : d->previousFocusableNode(0, event); node = deepFocusableNode(direction, node, event); if (!node) return false; } ASSERT(node); if (node == document->focusedNode()) // Focus wrapped around to the same node. return true; if (!node->isElementNode()) // FIXME: May need a way to focus a document here. return false; if (node->isFrameOwnerElement()) { // We focus frames rather than frame owners. // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user. HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node); if (!owner->contentFrame()) return false; document->setFocusedNode(0); setFocusedFrame(owner->contentFrame()); return true; } // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in // their focus() methods. Document* newDocument = node->document(); if (newDocument != document) // Focus is going away from this document, so clear the focused node. document->setFocusedNode(0); if (newDocument) setFocusedFrame(newDocument->frame()); if (caretBrowsing) { VisibleSelection newSelection(Position(node, 0), Position(node, 0), DOWNSTREAM); if (frame->shouldChangeSelection(newSelection)) frame->selection()->setSelection(newSelection); } static_cast<Element*>(node)->focus(false); return true; }
static JSValueRef addSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/) { JSValueRef undefined = JSValueMakeUndefined(ctx); InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); if (argumentCount < 2 || !controller) return undefined; JSValueRef identifierValue = arguments[0]; if (!JSValueIsNumber(ctx, identifierValue)) return undefined; unsigned long identifier = static_cast<unsigned long>(JSValueToNumber(ctx, identifierValue, 0)); RefPtr<InspectorResource> resource = controller->resources().get(identifier); ASSERT(resource); if (!resource) return undefined; RefPtr<SharedBuffer> buffer; if (resource->requestURL == resource->loader->requestURL()) buffer = resource->loader->mainResourceData(); else { FrameLoader* frameLoader = resource->loader->frameLoader(); if (!frameLoader) return undefined; Document* doc = frameLoader->frame()->document(); if (!doc) return undefined; CachedResource* cachedResource = doc->docLoader()->cachedResource(resource->requestURL.url()); if (!cachedResource) return undefined; buffer = cachedResource->data(); } if (!buffer) return undefined; String textEncodingName = resource->loader->overrideEncoding(); if (!textEncodingName) textEncodingName = resource->textEncodingName; TextEncoding encoding(textEncodingName); if (!encoding.isValid()) encoding = WindowsLatin1Encoding(); String sourceString = encoding.decode(buffer->data(), buffer->size()); Node* node = toNode(toJS(arguments[1])); ASSERT(node); if (!node) return undefined; if (!node->attached()) { ASSERT_NOT_REACHED(); return undefined; } ASSERT(node->isElementNode()); if (!node->isElementNode()) return undefined; Element* element = static_cast<Element*>(node); ASSERT(element->isFrameOwnerElement()); if (!element->isFrameOwnerElement()) return undefined; HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element); ASSERT(frameOwner->contentFrame()); if (!frameOwner->contentFrame()) return undefined; FrameLoader* loader = frameOwner->contentFrame()->loader(); loader->setResponseMIMEType(resource->mimeType); loader->begin(); loader->write(sourceString); loader->end(); return undefined; }