bool FatFingers::checkForClickableElement(Element* curElement, Vector<IntersectingRegion>& intersectingRegions, Platform::IntRectRegion& remainingFingerRegion, RenderLayer*& lowestPositionedEnclosingLayerSoFar) { ASSERT(curElement); bool intersects = false; Platform::IntRectRegion elementRegion; bool isClickableElement = isElementClickable(curElement); if (isClickableElement) { if (curElement->isLink()) { // Links can wrap lines, and in such cases Node::getRect() can give us // not accurate rects, since it unites all InlineBox's rects. In these // cases, we can process each line of the link separately with our // intersection rect, getting a more accurate clicking. Vector<FloatQuad> quads; curElement->renderer()->absoluteFocusRingQuads(quads); size_t n = quads.size(); ASSERT(n); for (size_t i = 0; i < n; ++i) elementRegion = unionRegions(elementRegion, Platform::IntRect(quads[i].enclosingBoundingBox())); } else elementRegion = Platform::IntRectRegion(curElement->renderer()->absoluteBoundingBoxRect(true /*use transforms*/)); } else elementRegion = Platform::IntRectRegion(curElement->renderer()->absoluteBoundingBoxRect(true /*use transforms*/)); if (lowestPositionedEnclosingLayerSoFar) { RenderLayer* curElementRenderLayer = m_webPage->enclosingPositionedAncestorOrSelfIfPositioned(curElement->renderer()->enclosingLayer()); if (curElementRenderLayer != lowestPositionedEnclosingLayerSoFar) { // elementRegion will always be in contents coordinates of its container frame. It needs to be // mapped to main frame contents coordinates in order to subtract the fingerRegion, then. WebCore::IntPoint framePos(m_webPage->frameOffset(curElement->document()->frame())); Platform::IntRectRegion layerRegion(Platform::IntRect(lowestPositionedEnclosingLayerSoFar->renderer()->absoluteBoundingBoxRect(true/*use transforms*/))); layerRegion.move(framePos.x(), framePos.y()); remainingFingerRegion = subtractRegions(remainingFingerRegion, layerRegion); lowestPositionedEnclosingLayerSoFar = curElementRenderLayer; } } else lowestPositionedEnclosingLayerSoFar = m_webPage->enclosingPositionedAncestorOrSelfIfPositioned(curElement->renderer()->enclosingLayer()); if (isClickableElement) intersects = checkFingerIntersection(elementRegion, remainingFingerRegion, curElement, intersectingRegions); return intersects; }
const FatFingersResult FatFingers::findBestPoint() { ASSERT(m_webPage); ASSERT(m_webPage->m_mainFrame); m_cachedRectHitTestResults.clear(); FatFingersResult result(m_contentPos); m_matchingApproach = ClickableByDefault; // Lets set nodeUnderFatFinger to the result of a point based hit test here. If something // targable is actually found by ::findIntersectingRegions, then we might replace what we just set below later on. Element* elementUnderPoint; Element* clickableElementUnderPoint; getRelevantInfoFromPoint(m_webPage->m_mainFrame->document(), m_contentPos, elementUnderPoint, clickableElementUnderPoint); if (elementUnderPoint) { result.m_nodeUnderFatFinger = elementUnderPoint; // If we are looking for a Clickable Element and we found one, we can quit early. if (m_targetType == ClickableElement) { if (clickableElementUnderPoint) { setSuccessfulFatFingersResult(result, clickableElementUnderPoint, m_contentPos /*adjustedPosition*/); return result; } if (isElementClickable(elementUnderPoint)) { setSuccessfulFatFingersResult(result, elementUnderPoint, m_contentPos /*adjustedPosition*/); return result; } } } #if DEBUG_FAT_FINGERS // Force blit to make the fat fingers rects show up. if (!m_debugFatFingerRect.isEmpty()) m_webPage->m_backingStore->repaint(0, 0, m_webPage->transformedViewportSize().width(), m_webPage->transformedViewportSize().height(), true, true); #endif Vector<IntersectingRegion> intersectingRegions; Platform::IntRectRegion remainingFingerRegion = Platform::IntRectRegion(fingerRectForPoint(m_contentPos)); bool foundOne = findIntersectingRegions(m_webPage->m_mainFrame->document(), intersectingRegions, remainingFingerRegion); if (!foundOne) { m_matchingApproach = MadeClickableByTheWebpage; remainingFingerRegion = Platform::IntRectRegion(fingerRectForPoint(m_contentPos)); foundOne = findIntersectingRegions(m_webPage->m_mainFrame->document(), intersectingRegions, remainingFingerRegion); } m_matchingApproach = Done; m_cachedRectHitTestResults.clear(); if (!foundOne) return result; Node* bestNode = 0; Platform::IntRectRegion largestIntersectionRegion; IntPoint bestPoint; int largestIntersectionRegionArea = 0; Vector<IntersectingRegion>::const_iterator endIt = intersectingRegions.end(); for (Vector<IntersectingRegion>::const_iterator it = intersectingRegions.begin(); it != endIt; ++it) { Node* currentNode = it->first; Platform::IntRectRegion currentIntersectionRegion = it->second; int currentIntersectionRegionArea = currentIntersectionRegion.area(); if (currentIntersectionRegionArea > largestIntersectionRegionArea || (currentIntersectionRegionArea == largestIntersectionRegionArea && compareDistanceBetweenPoints(m_contentPos, currentIntersectionRegion, largestIntersectionRegion))) { bestNode = currentNode; largestIntersectionRegion = currentIntersectionRegion; largestIntersectionRegionArea = currentIntersectionRegionArea; } } if (!bestNode || largestIntersectionRegion.isEmpty()) return result; #if DEBUG_FAT_FINGERS m_debugFatFingerAdjustedPosition = m_webPage->mapToTransformed(m_webPage->mapFromContentsToViewport(largestIntersectionRegion.rects()[0].center())); #endif setSuccessfulFatFingersResult(result, bestNode, largestIntersectionRegion.rects()[0].center() /*adjustedPosition*/); return result; }
const FatFingersResult FatFingers::findBestPoint() { ASSERT(m_webPage); ASSERT(m_webPage->m_mainFrame); // Even though we have clamped the point in libwebview to viewport, but there might be a rounding difference for viewport rect. // Clamp position to viewport to ensure we are inside viewport. IntRect viewportRect = m_webPage->mainFrame()->view()->visibleContentRect(); m_contentPos = Platform::pointClampedToRect(m_contentPos, viewportRect); m_cachedRectHitTestResults.clear(); FatFingersResult result(m_contentPos); // Lets set nodeUnderFatFinger to the result of a point based hit test here. If something // targable is actually found by ::findIntersectingRegions, then we might replace what we just set below later on. const HitTestResult& hitResult = m_webPage->hitTestResult(m_contentPos); Node* node = hitResult.innerNode(); while (node && !node->isElementNode()) node = node->parentNode(); Element* elementUnderPoint = static_cast<Element*>(node); if (elementUnderPoint) { result.m_nodeUnderFatFinger = elementUnderPoint; // If we are looking for a Clickable Element and we found one, we can quit early. if (m_targetType == ClickableElement) { if (isElementClickable(elementUnderPoint)) { setSuccessfulFatFingersResult(result, elementUnderPoint, m_contentPos /*adjustedPosition*/); return result; } if (hitResult.URLElement()) { setSuccessfulFatFingersResult(result, hitResult.URLElement(), m_contentPos /*adjustedPosition*/); return result; } } } #if DEBUG_FAT_FINGERS // Force blit to make the fat fingers rects show up. if (!m_debugFatFingerRect.isEmpty()) m_webPage->m_backingStore->repaint(0, 0, m_webPage->transformedViewportSize().width(), m_webPage->transformedViewportSize().height(), true, true); #endif Vector<IntersectingRegion> intersectingRegions; IntRectRegion remainingFingerRegion = IntRectRegion(fingerRectForPoint(m_contentPos)); bool foundOne = findIntersectingRegions(m_webPage->m_mainFrame->document(), intersectingRegions, remainingFingerRegion); m_cachedRectHitTestResults.clear(); if (!foundOne) return result; Node* bestNode = 0; IntRectRegion largestIntersectionRegion; int largestIntersectionRegionArea = 0; Vector<IntersectingRegion>::const_iterator endIt = intersectingRegions.end(); for (Vector<IntersectingRegion>::const_iterator it = intersectingRegions.begin(); it != endIt; ++it) { Node* currentNode = it->first; IntRectRegion currentIntersectionRegion = it->second; int currentIntersectionRegionArea = currentIntersectionRegion.area(); if (currentIntersectionRegionArea > largestIntersectionRegionArea || (currentIntersectionRegionArea == largestIntersectionRegionArea && compareDistanceBetweenPoints(m_contentPos, currentIntersectionRegion, largestIntersectionRegion))) { bestNode = currentNode; largestIntersectionRegion = currentIntersectionRegion; largestIntersectionRegionArea = currentIntersectionRegionArea; } } if (!bestNode || largestIntersectionRegion.isEmpty()) return result; #if DEBUG_FAT_FINGERS const Platform::ViewportAccessor* viewportAccessor = m_webPage->m_webkitThreadViewportAccessor; m_debugFatFingerAdjustedPosition = viewportAccessor->pixelViewportFromContents( viewportAccessor->roundToPixelFromDocumentContents(largestIntersectionRegion.rects()[0].center())); #endif setSuccessfulFatFingersResult(result, bestNode, largestIntersectionRegion.rects()[0].center() /*adjustedPosition*/); return result; }