Exemple #1
0
void Board::checkClick(Vector2i clickPosition, RenderWindow &app)
{
    IntRect controlsArea = IntRect(app.getSize().x - 100, 10, 100, 30);
    if(controlsArea.contains(clickPosition))
    {
        showHelp = !showHelp;
    }
}
Exemple #2
0
void TiledBackingStore::computeCoverAndKeepRect(const IntRect& visibleRect, IntRect& coverRect, IntRect& keepRect) const
{
    coverRect = visibleRect;
    keepRect = visibleRect;

    // If we cover more that the actual viewport we can be smart about which tiles we choose to render.
    if (m_coverAreaMultiplier > 1) {
        // The initial cover area covers equally in each direction, according to the coverAreaMultiplier.
        coverRect.inflateX(visibleRect.width() * (m_coverAreaMultiplier - 1) / 2);
        coverRect.inflateY(visibleRect.height() * (m_coverAreaMultiplier - 1) / 2);
        keepRect = coverRect;

        if (m_trajectoryVector != FloatPoint::zero()) {
            // A null trajectory vector (no motion) means that tiles for the coverArea will be created.
            // A non-null trajectory vector will shrink the covered rect to visibleRect plus its expansion from its
            // center toward the cover area edges in the direction of the given vector.

            // E.g. if visibleRect == (10,10)5x5 and coverAreaMultiplier == 3.0:
            // a (0,0) trajectory vector will create tiles intersecting (5,5)15x15,
            // a (1,0) trajectory vector will create tiles intersecting (10,10)10x5,
            // and a (1,1) trajectory vector will create tiles intersecting (10,10)10x10.

            // Multiply the vector by the distance to the edge of the cover area.
            float trajectoryVectorMultiplier = (m_coverAreaMultiplier - 1) / 2;

            // Unite the visible rect with a "ghost" of the visible rect moved in the direction of the trajectory vector.
            coverRect = visibleRect;
            coverRect.move(coverRect.width() * m_trajectoryVector.x() * trajectoryVectorMultiplier,
                           coverRect.height() * m_trajectoryVector.y() * trajectoryVectorMultiplier);

            coverRect.unite(visibleRect);
        }
        ASSERT(keepRect.contains(coverRect));
    }

    adjustForContentsRect(coverRect);

    // The keep rect is an inflated version of the cover rect, inflated in tile dimensions.
    keepRect.unite(coverRect);
    keepRect.inflateX(m_tileSize.width() / 2);
    keepRect.inflateY(m_tileSize.height() / 2);
    keepRect.intersect(m_rect);

    ASSERT(coverRect.isEmpty() || keepRect.contains(coverRect));
}
Exemple #3
0
IntPoint determineHotSpot(Image* image, const IntPoint& specifiedHotSpot)
{
    if (image->isNull())
        return IntPoint();

    // Hot spot must be inside cursor rectangle.
    IntRect imageRect = image->rect();
    if (imageRect.contains(specifiedHotSpot))
        return specifiedHotSpot;

    // If hot spot is not specified externally, it can be extracted from some image formats (e.g. .cur).
    IntPoint intrinsicHotSpot;
    bool imageHasIntrinsicHotSpot = image->getHotSpot(intrinsicHotSpot);
    if (imageHasIntrinsicHotSpot && imageRect.contains(intrinsicHotSpot))
        return intrinsicHotSpot;

    return IntPoint();
}
Exemple #4
0
ScrollbarPart ScrollbarTheme::hitTest(const ScrollbarThemeClient& scrollbar,
                                      const IntPoint& positionInRootFrame) {
  ScrollbarPart result = NoPart;
  if (!scrollbar.enabled())
    return result;

  IntPoint testPosition = scrollbar.convertFromRootFrame(positionInRootFrame);
  testPosition.move(scrollbar.x(), scrollbar.y());

  if (!scrollbar.frameRect().contains(testPosition))
    return NoPart;

  result = ScrollbarBGPart;

  IntRect track = trackRect(scrollbar);
  if (track.contains(testPosition)) {
    IntRect beforeThumbRect;
    IntRect thumbRect;
    IntRect afterThumbRect;
    splitTrack(scrollbar, track, beforeThumbRect, thumbRect, afterThumbRect);
    if (thumbRect.contains(testPosition))
      result = ThumbPart;
    else if (beforeThumbRect.contains(testPosition))
      result = BackTrackPart;
    else if (afterThumbRect.contains(testPosition))
      result = ForwardTrackPart;
    else
      result = TrackBGPart;
  } else if (backButtonRect(scrollbar, BackButtonStartPart)
                 .contains(testPosition)) {
    result = BackButtonStartPart;
  } else if (backButtonRect(scrollbar, BackButtonEndPart)
                 .contains(testPosition)) {
    result = BackButtonEndPart;
  } else if (forwardButtonRect(scrollbar, ForwardButtonStartPart)
                 .contains(testPosition)) {
    result = ForwardButtonStartPart;
  } else if (forwardButtonRect(scrollbar, ForwardButtonEndPart)
                 .contains(testPosition)) {
    result = ForwardButtonEndPart;
  }
  return result;
}
Exemple #5
0
// This function is a bit of a mystery. If you understand what it does, please
// consider adding a more descriptive name.
Node* SmartClip::minNodeContainsNodes(Node* minNode, Node* newNode)
{
    if (!newNode)
        return minNode;
    if (!minNode)
        return newNode;

    IntRect minNodeRect = minNode->pixelSnappedBoundingBox();
    IntRect newNodeRect = newNode->pixelSnappedBoundingBox();

    Node* parentMinNode = minNode->parentNode();
    Node* parentNewNode = newNode->parentNode();

    if (minNodeRect.contains(newNodeRect)) {
        if (parentMinNode && parentNewNode && parentNewNode->parentNode() == parentMinNode)
            return parentMinNode;
        return minNode;
    }

    if (newNodeRect.contains(minNodeRect)) {
        if (parentMinNode && parentNewNode && parentMinNode->parentNode() == parentNewNode)
            return parentNewNode;
        return newNode;
    }

    // This loop appears to find the nearest ancestor of minNode (in DOM order)
    // that contains the newNodeRect. It's very unclear to me why that's an
    // interesting node to find. Presumably this loop will often just return
    // the documentElement.
    Node* node = minNode;
    while (node) {
        if (node->renderer()) {
            IntRect nodeRect = node->pixelSnappedBoundingBox();
            if (nodeRect.contains(newNodeRect)) {
                return node;
            }
        }
        node = node->parentNode();
    }

    return 0;
}
bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
{
    if (!m_thumb || !m_thumb->renderer())
        return false;
 
    ASSERT(evt->target()->toNode() == node());
    
    IntRect thumbBounds = m_thumb->renderer()->absoluteBoundingBoxRect();
    thumbBounds.setX(m_thumb->renderer()->style()->left().value());
    thumbBounds.setY(m_thumb->renderer()->style()->top().value());
    
    return thumbBounds.contains(evt->offsetX(), evt->offsetY());
}
ScrollbarPart ScrollbarThemeComposite::hitTest(ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& evt)
{
    ScrollbarPart result = NoPart;
    if (!scrollbar->enabled())
        return result;

    IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.position());
    mousePosition.move(scrollbar->x(), scrollbar->y());
    
    if (!scrollbar->frameRect().contains(mousePosition))
        return NoPart;

    result = ScrollbarBGPart;

    IntRect track = trackRect(scrollbar);
    if (track.contains(mousePosition)) {
        IntRect beforeThumbRect;
        IntRect thumbRect;
        IntRect afterThumbRect;
        splitTrack(scrollbar, track, beforeThumbRect, thumbRect, afterThumbRect);
        if (thumbRect.contains(mousePosition))
            result = ThumbPart;
        else if (beforeThumbRect.contains(mousePosition))
            result = BackTrackPart;
        else if (afterThumbRect.contains(mousePosition))
            result = ForwardTrackPart;
        else
            result = TrackBGPart;
    } else if (backButtonRect(scrollbar, BackButtonStartPart).contains(mousePosition))
        result = BackButtonStartPart;
    else if (backButtonRect(scrollbar, BackButtonEndPart).contains(mousePosition))
        result = BackButtonEndPart;
    else if (forwardButtonRect(scrollbar, ForwardButtonStartPart).contains(mousePosition))
        result = ForwardButtonStartPart;
    else if (forwardButtonRect(scrollbar, ForwardButtonEndPart).contains(mousePosition))
        result = ForwardButtonEndPart;
    return result;
}
static void write(TextStream& ts, RenderLayer& l,
                  const IntRect& layerBounds, const IntRect& backgroundClipRect, const IntRect& clipRect, const IntRect& outlineClipRect,
                  int layerType = 0, int indent = 0)
{
    writeIndent(ts, indent);

    ts << "layer " << layerBounds;

    if (!layerBounds.isEmpty()) {
        if (!backgroundClipRect.contains(layerBounds))
            ts << " backgroundClip " << backgroundClipRect;
        if (!clipRect.contains(layerBounds))
            ts << " clip " << clipRect;
        if (!outlineClipRect.contains(layerBounds))
            ts << " outlineClip " << outlineClipRect;
    }

    if (l.renderer()->hasOverflowClip()) {
        if (l.scrollXOffset())
            ts << " scrollX " << l.scrollXOffset();
        if (l.scrollYOffset())
            ts << " scrollY " << l.scrollYOffset();
        if (l.renderer()->clientWidth() != l.scrollWidth())
            ts << " scrollWidth " << l.scrollWidth();
        if (l.renderer()->clientHeight() != l.scrollHeight())
            ts << " scrollHeight " << l.scrollHeight();
    }

    if (layerType == -1)
        ts << " layerType: background only";
    else if (layerType == 1)
        ts << " layerType: foreground only";

    ts << "\n";

    if (layerType != -1)
        write(ts, *l.renderer(), indent + 1);
}
void RotationViewportAnchor::setAnchor()
{
    // FIXME: Scroll offsets are now fractional (DoublePoint and FloatPoint for the FrameView and VisualViewport
    //        respectively. This path should be rewritten without pixel snapping.
    IntRect outerViewRect = m_rootFrameView->layoutViewportScrollableArea()->visibleContentRect(IncludeScrollbars);
    IntRect innerViewRect = enclosedIntRect(m_rootFrameView->getScrollableArea()->visibleContentRectDouble());

    m_oldPageScaleFactor = m_visualViewport->scale();
    m_oldMinimumPageScaleFactor = m_pageScaleConstraintsSet.finalConstraints().minimumScale;

    // Save the absolute location in case we won't find the anchor node, we'll fall back to that.
    m_visualViewportInDocument = FloatPoint(m_rootFrameView->getScrollableArea()->visibleContentRectDouble().location());

    m_anchorNode.clear();
    m_anchorNodeBounds = LayoutRect();
    m_anchorInNodeCoords = FloatSize();
    m_normalizedVisualViewportOffset = FloatSize();

    if (innerViewRect.isEmpty())
        return;

    // Preserve origins at the absolute screen origin
    if (innerViewRect.location() == IntPoint::zero())
        return;

    // Inner rectangle should be within the outer one.
    DCHECK(outerViewRect.contains(innerViewRect));

    // Outer rectangle is used as a scale, we need positive width and height.
    DCHECK(!outerViewRect.isEmpty());

    m_normalizedVisualViewportOffset = FloatSize(innerViewRect.location() - outerViewRect.location());

    // Normalize by the size of the outer rect
    m_normalizedVisualViewportOffset.scale(1.0 / outerViewRect.width(), 1.0 / outerViewRect.height());

    FloatSize anchorOffset(innerViewRect.size());
    anchorOffset.scale(m_anchorInInnerViewCoords.width(), m_anchorInInnerViewCoords.height());
    const FloatPoint anchorPoint = FloatPoint(innerViewRect.location()) + anchorOffset;

    Node* node = findNonEmptyAnchorNode(flooredIntPoint(anchorPoint), innerViewRect, m_rootFrameView->frame().eventHandler());
    if (!node)
        return;

    m_anchorNode = node;
    m_anchorNodeBounds = node->boundingBox();
    m_anchorInNodeCoords = anchorPoint - FloatPoint(m_anchorNodeBounds.location());
    m_anchorInNodeCoords.scale(1.f / m_anchorNodeBounds.width(), 1.f / m_anchorNodeBounds.height());
}
Exemple #10
0
bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const IntRect& rect)
{
    // If it is not a rect-based hit test, this method has to be no-op.
    // Return false, so the hit test stops.
    if (!isRectBasedTest())
        return false;

    // If node is null, return true so the hit test can continue.
    if (!node)
        return true;

    node = node->shadowAncestorNode();
    m_rectBasedTestResult.add(node);

    return !rect.contains(rectForPoint(x, y));
}
Exemple #11
0
void PicturePile::appendToPile(const IntRect& inval, const IntRect& originalInval)
{
    ALOGV("Adding inval " INT_RECT_FORMAT " for original inval " INT_RECT_FORMAT,
            INT_RECT_ARGS(inval), INT_RECT_ARGS(originalInval));
    // Remove any entries this obscures
    for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
        if (inval.contains(m_pile[i].area))
            m_pile.remove(i);
    }
    PictureContainer container(inval);
    if (ENABLE_PRERENDERED_INVALS) {
        container.prerendered = PrerenderedInval::create(originalInval.isEmpty()
                                                         ? inval : originalInval);
    }
    m_pile.append(container);
}
Exemple #12
0
// This returns quotient of the target area and its intersection with the touch area.
// This will prioritize largest intersection and smallest area, while balancing the two against each other.
float zoomableIntersectionQuotient(const IntPoint& touchHotspot, const IntRect& touchArea, const SubtargetGeometry& subtarget)
{
    IntRect rect = subtarget.boundingBox();

    // Convert from frame coordinates to window coordinates.
    rect = subtarget.node()->document()->view()->contentsToWindow(rect);

    // Check the rectangle is meaningful zoom target. It should at least contain the hotspot.
    if (!rect.contains(touchHotspot))
        return std::numeric_limits<float>::infinity();
    IntRect intersection = rect;
    intersection.intersect(touchArea);

    // Return the quotient of the intersection.
    return rect.size().area() / (float)intersection.size().area();
}
bool RenderSlider::mouseEventIsInThumb(MouseEvent* evt)
{
    if (!m_thumb || !m_thumb->renderer())
        return false;

#if ENABLE(VIDEO)
    if (style()->appearance() == MediaSliderPart || style()->appearance() == MediaVolumeSliderPart) {
        MediaControlInputElement *sliderThumb = static_cast<MediaControlInputElement*>(m_thumb->renderer()->node());
        return sliderThumb->hitTest(evt->absoluteLocation());
    }
#endif

    FloatPoint localPoint = m_thumb->renderBox()->absoluteToLocal(evt->absoluteLocation(), false, true);
    IntRect thumbBounds = m_thumb->renderBox()->borderBoxRect();
    return thumbBounds.contains(roundedIntPoint(localPoint));
}
Exemple #14
0
bool ScrollbarThemeWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt)
{
    // Find the rect within which we shouldn't snap, by expanding the track rect
    // in both dimensions.
    IntRect rect = trackRect(scrollbar);
    const bool horz = scrollbar->orientation() == HorizontalScrollbar;
    const int thickness = scrollbarThickness(scrollbar->controlSize());
    rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness);
    rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness);

    // Convert the event to local coordinates.
    IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos());
    mousePosition.move(scrollbar->x(), scrollbar->y());

    // We should snap iff the event is outside our calculated rect.
    return !rect.contains(mousePosition);
}
Exemple #15
0
void SliderThumbElement::handleTouchStart(TouchEvent* touchEvent)
{
    TouchList* targetTouches = touchEvent->targetTouches();
    if (targetTouches->length() != 1)
        return;

    // Ignore the touch if it is not really inside the thumb.
    Touch* touch = targetTouches->item(0);
    IntRect boundingBox = renderer()->absoluteBoundingBoxRect();
    if (!boundingBox.contains(touch->pageX(), touch->pageY()))
        return;

    setExclusiveTouchIdentifier(touch->identifier());

    startDragging();
    touchEvent->setDefaultHandled();
}
void TiledBackingStore::dropOverhangingTiles()
{    
    IntRect contentsRect = this->contentsRect();

    Vector<Tile::Coordinate> tilesToRemove;
    TileMap::iterator end = m_tiles.end();
    for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) {
        Tile::Coordinate tileCoordinate = it->second->coordinate();
        IntRect tileRect = it->second->rect();
        IntRect expectedTileRect = tileRectForCoordinate(tileCoordinate);
        if (expectedTileRect != tileRect || !contentsRect.contains(tileRect))
            tilesToRemove.append(tileCoordinate);
    }
    unsigned removeCount = tilesToRemove.size();
    for (unsigned n = 0; n < removeCount; ++n)
        removeTile(tilesToRemove[n]);
}
Exemple #17
0
bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const IntRect& touchArea, IntPoint& adjustedPoint)
{
    FrameView* view = geom.node()->document()->view();
    FloatQuad quad = geom.quad();

    if (quad.isRectilinear()) {
        IntRect contentBounds = geom.boundingBox();
        // Convert from frame coordinates to window coordinates.
        IntRect bounds = view->contentsToWindow(contentBounds);
        if (bounds.contains(touchPoint)) {
            adjustedPoint = touchPoint;
            return true;
        }
        if (bounds.intersects(touchArea)) {
            bounds.intersect(touchArea);
            adjustedPoint = bounds.center();
            return true;
        }
        return false;
    }

    // The following code tries to adjust the point to place inside a both the touchArea and the non-rectilinear quad.
    // FIXME: This will return the point inside the touch area that is the closest to the quad center, but does not
    // guarantee that the point will be inside the quad. Corner-cases exist where the quad will intersect but this
    // will fail to adjust the point to somewhere in the intersection.

    // Convert quad from content to window coordinates.
    FloatPoint p1 = contentsToWindow(view, quad.p1());
    FloatPoint p2 = contentsToWindow(view, quad.p2());
    FloatPoint p3 = contentsToWindow(view, quad.p3());
    FloatPoint p4 = contentsToWindow(view, quad.p4());
    quad = FloatQuad(p1, p2, p3, p4);

    if (quad.containsPoint(touchPoint)) {
        adjustedPoint = touchPoint;
        return true;
    }

    // Pull point towards the center of the element.
    FloatPoint center = quad.center();

    adjustPointToRect(center, touchArea);
    adjustedPoint = roundedIntPoint(center);

    return quad.containsPoint(adjustedPoint);
}
Exemple #18
0
void ViewportAnchor::setAnchor(const IntRect& outerViewRect, const IntRect& innerViewRect,
    const FloatSize& anchorInInnerViewCoords)
{
    // Preserve the inner viewport position in document in case we won't find the anchor
    m_pinchViewportInDocument = innerViewRect.location();

    m_anchorNode.clear();
    m_anchorNodeBounds = LayoutRect();
    m_anchorInNodeCoords = FloatSize();
    m_anchorInInnerViewCoords = anchorInInnerViewCoords;
    m_normalizedPinchViewportOffset = FloatSize();

    if (innerViewRect.isEmpty())
        return;

    // Preserve origins at the absolute screen origin
    if (innerViewRect.location() == IntPoint::zero())
        return;

    // Inner rectangle should be within the outer one.
    ASSERT(outerViewRect.contains(innerViewRect));

    // Outer rectangle is used as a scale, we need positive width and height.
    ASSERT(!outerViewRect.isEmpty());

    m_normalizedPinchViewportOffset = innerViewRect.location() - outerViewRect.location();

    // Normalize by the size of the outer rect
    m_normalizedPinchViewportOffset.scale(1.0 / outerViewRect.width(), 1.0 / outerViewRect.height());

    FloatSize anchorOffset = innerViewRect.size();
    anchorOffset.scale(anchorInInnerViewCoords.width(), anchorInInnerViewCoords.height());
    const FloatPoint anchorPoint = FloatPoint(innerViewRect.location()) + anchorOffset;

    Node* node = findNonEmptyAnchorNode(flooredIntPoint(anchorPoint), innerViewRect, m_eventHandler);
    if (!node)
        return;

    m_anchorNode = node;
    m_anchorNodeBounds = node->boundingBox();
    m_anchorInNodeCoords = anchorPoint - FloatPoint(m_anchorNodeBounds.location());
    m_anchorInNodeCoords.scale(1.f / m_anchorNodeBounds.width(), 1.f / m_anchorNodeBounds.height());
}
static void accumulateRendererTouchEventTargetRects(Vector<IntRect>& rects, const RenderObject* renderer, const IntRect& parentRect = IntRect())
{
    IntRect adjustedParentRect = parentRect;
    if (parentRect.isEmpty() || renderer->isFloating() || renderer->isPositioned() || renderer->hasTransform()) {
        // FIXME: This method is O(N^2) as it walks the tree to the root for every renderer. RenderGeometryMap would fix this.
        IntRect r = enclosingIntRect(renderer->clippedOverflowRectForRepaint(0));
        if (!r.isEmpty()) {
            // Convert to the top-level view's coordinates.
            ASSERT(renderer->document()->view());
            r = renderer->document()->view()->convertToRootView(r);

            if (!parentRect.contains(r)) {
                rects.append(r);
                adjustedParentRect = r;
            }
        }
    }

    for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling())
        accumulateRendererTouchEventTargetRects(rects, child, adjustedParentRect);
}
Exemple #20
0
void ChromeClientImpl::popupOpened(PopupContainer* popupContainer,
                                   const IntRect& bounds,
                                   bool handleExternally)
{
    // For Autofill popups, if the popup will not be fully visible, we shouldn't
    // show it at all. Among other things, this prevents users from being able
    // to interact via the keyboard with an invisible popup.
    if (popupContainer->popupType() == PopupContainer::Suggestion) {
        FrameView* view = m_webView->page()->mainFrame()->view();
        IntRect visibleRect = view->visibleContentRect(true /* include scrollbars */);
        // |bounds| is in screen coordinates, so make sure to convert it to
        // content coordinates prior to comparing to |visibleRect|.
        IntRect screenRect = bounds;
        screenRect.setLocation(view->screenToContents(bounds.location()));
        if (!visibleRect.contains(screenRect)) {
            m_webView->hideAutofillPopup();
            return;
        }
    }

    if (!m_webView->client())
        return;

    WebWidget* webwidget;
    if (handleExternally) {
        WebPopupMenuInfo popupInfo;
        getPopupMenuInfo(popupContainer, &popupInfo);
        webwidget = m_webView->client()->createPopupMenu(popupInfo);
    } else {
        webwidget = m_webView->client()->createPopupMenu(
            convertPopupType(popupContainer->popupType()));
        // We only notify when the WebView has to handle the popup, as when
        // the popup is handled externally, the fact that a popup is showing is
        // transparent to the WebView.
        m_webView->popupOpened(popupContainer);
    }
    static_cast<WebPopupMenuImpl*>(webwidget)->init(popupContainer, bounds);
}
Exemple #21
0
bool TiledDrawingAreaProxy::resizeEdgeTiles()
{
    IntRect contentsRect = this->contentsRect();
    bool wasResized = false;

    Vector<TiledDrawingAreaTile::Coordinate> tilesToRemove;
    TileMap::iterator end = m_tiles.end();
    for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) {
        TiledDrawingAreaTile::Coordinate tileCoordinate = it->second->coordinate();
        IntRect tileRect = it->second->rect();
        IntRect expectedTileRect = tileRectForCoordinate(tileCoordinate);
        if (!contentsRect.contains(tileRect))
            tilesToRemove.append(tileCoordinate);
        else if (expectedTileRect != tileRect) {
            it->second->resize(expectedTileRect.size());
            wasResized = true;
        }
    }
    unsigned removeCount = tilesToRemove.size();
    for (unsigned n = 0; n < removeCount; ++n)
        removeTile(tilesToRemove[n]);
    return wasResized;
}
LRESULT WebPopupMenuProxyWin::onMouseMove(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled)
{
    handled = true;

    IntPoint mousePoint(MAKEPOINTS(lParam));
    if (scrollbar()) {
        IntRect scrollBarRect = scrollbar()->frameRect();
        if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) {
            // Put the point into coordinates relative to the scroll bar
            mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
            PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y()));
            scrollbar()->mouseMoved(event);
            return 0;
        }
    }

    BOOL shouldHotTrack = FALSE;
    ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0);

    RECT bounds;
    ::GetClientRect(m_popup, &bounds);
    if (!::PtInRect(&bounds, mousePoint) && !(wParam & MK_LBUTTON)) {
        // When the mouse is not inside the popup menu and the left button isn't down, just
        // repost the message to the web view.

        // Translate the coordinate.
        translatePoint(lParam, m_popup, m_webView->window());

        ::PostMessage(m_popup, WM_HOST_WINDOW_MOUSEMOVE, wParam, lParam);
        return 0;
    }

    if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, mousePoint))
        setFocusedIndex(listIndexAtPoint(mousePoint), true);

    return 0;
}
bool RenderSVGViewportContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
{
    if (!viewport().isEmpty()
            && style()->overflowX() == OHIDDEN
            && style()->overflowY() == OHIDDEN) {
        // Check if we need to do anything at all.
        IntRect overflowBox = IntRect(0, 0, width(), height());
        overflowBox.move(_tx, _ty);
        TransformationMatrix ctm = RenderObject::absoluteTransform();
        ctm.translate(viewport().x(), viewport().y());
        double localX, localY;
        ctm.inverse().map(_x - _tx, _y - _ty, &localX, &localY);
        if (!overflowBox.contains((int)localX, (int)localY))
            return false;
    }

    int sx = 0;
    int sy = 0;

    // Respect parent translation offset for non-outermost <svg> elements.
    // Outermost <svg> element is handled by RenderSVGRoot.
    if (element()->hasTagName(SVGNames::svgTag)) {
        sx = _tx;
        sy = _ty;
    }

    for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
        if (child->nodeAtPoint(request, result, _x - sx, _y - sy, _tx, _ty, hitTestAction)) {
            updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty));
            return true;
        }
    }

    // Spec: Only graphical elements can be targeted by the mouse, period.
    // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched."
    return false;
}
static void write(TextStream& ts, RenderLayer& l,
                  const LayoutRect& layerBounds, const LayoutRect& backgroundClipRect,
                  int indent = 0, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal)
{
    IntRect adjustedLayoutBounds = pixelSnappedIntRect(layerBounds);
    IntRect adjustedBackgroundClipRect = pixelSnappedIntRect(backgroundClipRect);

    writeIndent(ts, indent);

    ts << "layer ";

    if (behavior & RenderAsTextShowAddresses)
        ts << static_cast<const void*>(&l) << " ";

    ts << adjustedLayoutBounds;

    if (!adjustedLayoutBounds.isEmpty()) {
        if (!adjustedBackgroundClipRect.contains(adjustedLayoutBounds))
            ts << " backgroundClip " << adjustedBackgroundClipRect;
    }

    ts << "\n";
    write(ts, *l.renderer(), indent + 1, behavior);
}
Exemple #25
0
//------------------------------------------------------------------------------
void Control::processMouseMove(Event & e)
{
    IntRect bounds = getClientBounds();
	bool hover = bounds.contains(e.value.mouse.x, e.value.mouse.y);
    if (hover)
    {
        if (!isHovered())
        {
            setControlFlag(TGUI_CF_HOVERED, true);
            onMouseEnter(e);
            onSetCursor(e);
        }
    }
    else if (isHovered())
    {
        setControlFlag(TGUI_CF_HOVERED, false);
        onMouseLeave(e);
    }
	if (hover || getControlFlag(TGUI_CF_CAPTURED))
	{
		onMouseMove(e);
        onSetCursor(e);
	}
}
Exemple #26
0
int Frame::checkOverflowScroll(OverflowScrollAction action)
{
    Position extent = selection().selection().extent();
    if (extent.isNull())
        return OverflowScrollNone;

    RenderObject* renderer = extent.deprecatedNode()->renderer();
    if (!renderer)
        return OverflowScrollNone;

    FrameView* view = this->view();
    if (!view)
        return OverflowScrollNone;

    RenderBlock* containingBlock = renderer->containingBlock();
    if (!containingBlock || !containingBlock->hasOverflowClip())
        return OverflowScrollNone;
    RenderLayer* layer = containingBlock->layer();
    ASSERT(layer);

    IntRect visibleRect = IntRect(view->scrollX(), view->scrollY(), view->visibleWidth(), view->visibleHeight());
    IntPoint position = m_overflowAutoScrollPos;
    if (visibleRect.contains(position.x(), position.y()))
        return OverflowScrollNone;

    int scrollType = 0;
    int deltaX = 0;
    int deltaY = 0;
    IntPoint selectionPosition;

    // This constant will make the selection draw a little bit beyond the edge of the visible area.
    // This prevents a visual glitch, in that you can fail to select a portion of a character that
    // is being rendered right at the edge of the visible rectangle.
    // FIXME: This probably needs improvement, and may need to take the font size into account.
    static const int scrollBoundsAdjustment = 3;

    // FIXME: Make a small buffer at the end of a visible rectangle so that autoscrolling works 
    // even if the visible extends to the limits of the screen.
    if (position.x() < visibleRect.x()) {
        scrollType |= OverflowScrollLeft;
        if (action == PerformOverflowScroll) {
            deltaX -= static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setX(view->scrollX() - scrollBoundsAdjustment);
        }
    } else if (position.x() > visibleRect.maxX()) {
        scrollType |= OverflowScrollRight;
        if (action == PerformOverflowScroll) {
            deltaX += static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setX(view->scrollX() + view->visibleWidth() + scrollBoundsAdjustment);
        }
    }

    if (position.y() < visibleRect.y()) {
        scrollType |= OverflowScrollUp;
        if (action == PerformOverflowScroll) {
            deltaY -= static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setY(view->scrollY() - scrollBoundsAdjustment);
        }
    } else if (position.y() > visibleRect.maxY()) {
        scrollType |= OverflowScrollDown;
        if (action == PerformOverflowScroll) {
            deltaY += static_cast<int>(m_overflowAutoScrollDelta);
            selectionPosition.setY(view->scrollY() + view->visibleHeight() + scrollBoundsAdjustment);
        }
    }

    Ref<Frame> protectedThis(*this);

    if (action == PerformOverflowScroll && (deltaX || deltaY)) {
        layer->scrollToOffset(layer->scrollOffset() + IntSize(deltaX, deltaY));

        // Handle making selection.
        VisiblePosition visiblePosition(renderer->positionForPoint(selectionPosition, nullptr));
        if (visiblePosition.isNotNull()) {
            VisibleSelection visibleSelection = selection().selection();
            visibleSelection.setExtent(visiblePosition);
            if (selection().granularity() != CharacterGranularity)
                visibleSelection.expandUsingGranularity(selection().granularity());
            if (selection().shouldChangeSelection(visibleSelection))
                selection().setSelection(visibleSelection);
        }

        m_overflowAutoScrollDelta *= 1.02f; // Accelerate the scroll
    }
    return scrollType;
}
Exemple #27
0
void TouchActionTest::runTestOnTree(ContainerNode* root,
                                    WebView* webView,
                                    TouchActionTrackingWebViewClient& client) {
  // Find all elements to test the touch-action of in the document.
  TrackExceptionState es;

  // Oilpan: see runTouchActionTest() comment why these are persistent
  // references.
  Persistent<StaticElementList> elements =
      root->querySelectorAll("[expected-action]", es);
  ASSERT_FALSE(es.hadException());

  for (unsigned index = 0; index < elements->length(); index++) {
    Element* element = elements->item(index);
    element->scrollIntoViewIfNeeded();

    std::string failureContext("Test case: ");
    if (element->hasID()) {
      failureContext.append(element->getIdAttribute().ascii().data());
    } else if (element->firstChild()) {
      failureContext.append("\"");
      failureContext.append(element->firstChild()
                                ->textContent(false)
                                .stripWhiteSpace()
                                .ascii()
                                .data());
      failureContext.append("\"");
    } else {
      failureContext += "<missing ID>";
    }

    // Run each test three times at different positions in the element.
    // Note that we don't want the bounding box because our tests sometimes have
    // elements with multiple border boxes with other elements in between. Use
    // the first border box (which we can easily visualize in a browser for
    // debugging).
    Persistent<ClientRectList> rects = element->getClientRects();
    ASSERT_GE(rects->length(), 0u) << failureContext;
    Persistent<ClientRect> r = rects->item(0);
    FloatRect clientFloatRect =
        FloatRect(r->left(), r->top(), r->width(), r->height());
    IntRect clientRect = enclosedIntRect(clientFloatRect);
    for (int locIdx = 0; locIdx < 3; locIdx++) {
      IntPoint framePoint;
      std::stringstream contextStream;
      contextStream << failureContext << " (";
      switch (locIdx) {
        case 0:
          framePoint = clientRect.center();
          contextStream << "center";
          break;
        case 1:
          framePoint = clientRect.location();
          contextStream << "top-left";
          break;
        case 2:
          framePoint = clientRect.maxXMaxYCorner();
          framePoint.move(-1, -1);
          contextStream << "bottom-right";
          break;
        default:
          FAIL() << "Invalid location index.";
      }

      IntPoint windowPoint =
          root->document().frame()->view()->convertToRootFrame(framePoint);
      contextStream << "=" << windowPoint.x() << "," << windowPoint.y() << ").";
      std::string failureContextPos = contextStream.str();

      LocalFrame* mainFrame =
          static_cast<LocalFrame*>(webView->mainFrame()->toImplBase()->frame());
      FrameView* mainFrameView = mainFrame->view();
      IntRect visibleRect = windowClipRect(*mainFrameView);
      ASSERT_TRUE(visibleRect.contains(windowPoint))
          << failureContextPos
          << " Test point not contained in visible area: " << visibleRect.x()
          << "," << visibleRect.y() << "-" << visibleRect.maxX() << ","
          << visibleRect.maxY();

      // First validate that a hit test at this point will really hit the
      // element we intended. This is the easiest way for a test to be broken,
      // but has nothing really to do with touch action.  Note that we can't use
      // WebView's hit test API because it doesn't look into shadow DOM.
      IntPoint docPoint(mainFrameView->frameToContents(windowPoint));
      HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint(
          docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
      ASSERT_EQ(element, result.innerElement())
          << "Unexpected hit test result " << failureContextPos
          << "  Got element: \""
          << result.innerElement()
                 ->outerHTML()
                 .stripWhiteSpace()
                 .left(80)
                 .ascii()
                 .data()
          << "\"" << std::endl
          << "Document render tree:" << std::endl
          << externalRepresentation(root->document().frame()).utf8().data();

      // Now send the touch event and check any touch action result.
      sendTouchEvent(webView, WebInputEvent::TouchStart, windowPoint);

      AtomicString expectedAction = element->getAttribute("expected-action");
      if (expectedAction == "auto") {
        // Auto is the default - no action set.
        EXPECT_EQ(0, client.touchActionSetCount()) << failureContextPos;
        EXPECT_EQ(WebTouchActionAuto, client.lastTouchAction())
            << failureContextPos;
      } else {
        // Should have received exactly one touch action.
        EXPECT_EQ(1, client.touchActionSetCount()) << failureContextPos;
        if (client.touchActionSetCount()) {
          if (expectedAction == "none") {
            EXPECT_EQ(WebTouchActionNone, client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "pan-x") {
            EXPECT_EQ(WebTouchActionPanX, client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "pan-y") {
            EXPECT_EQ(WebTouchActionPanY, client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "pan-x-y") {
            EXPECT_EQ((WebTouchActionPan), client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "manipulation") {
            EXPECT_EQ((WebTouchActionManipulation), client.lastTouchAction())
                << failureContextPos;
          } else {
            FAIL() << "Unrecognized expected-action \""
                   << expectedAction.ascii().data() << "\" "
                   << failureContextPos;
          }
        }
      }

      // Reset webview touch state.
      client.reset();
      sendTouchEvent(webView, WebInputEvent::TouchCancel, windowPoint);
      EXPECT_EQ(0, client.touchActionSetCount());
    }
  }
}
Exemple #28
0
LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT lResult = 0;

    switch (message) {
    case WM_MOUSEACTIVATE:
        return MA_NOACTIVATE;
    case WM_SIZE: {
        if (!scrollbar())
            break;

        IntSize size(LOWORD(lParam), HIWORD(lParam));
        scrollbar()->setFrameRect(IntRect(size.width() - scrollbar()->width(), 0, scrollbar()->width(), size.height()));

        int visibleItems = this->visibleItems();
        scrollbar()->setEnabled(visibleItems < client()->listSize());
        scrollbar()->setSteps(1, std::max(1, visibleItems - 1));
        scrollbar()->setProportion(visibleItems, client()->listSize());

        break;
    }
    case WM_SYSKEYDOWN:
    case WM_KEYDOWN: {
        if (!client())
            break;

        bool altKeyPressed = GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT;
        bool ctrlKeyPressed = GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT;

        lResult = 0;
        switch (LOWORD(wParam)) {
        case VK_F4: {
            if (!altKeyPressed && !ctrlKeyPressed) {
                int index = focusedIndex();
                ASSERT(index >= 0);
                client()->valueChanged(index);
                hide();
            }
            break;
        }
        case VK_DOWN:
            if (altKeyPressed) {
                int index = focusedIndex();
                ASSERT(index >= 0);
                client()->valueChanged(index);
                hide();
            } else
                down();
            break;
        case VK_RIGHT:
            down();
            break;
        case VK_UP:
            if (altKeyPressed) {
                int index = focusedIndex();
                ASSERT(index >= 0);
                client()->valueChanged(index);
                hide();
            } else
                up();
            break;
        case VK_LEFT:
            up();
            break;
        case VK_HOME:
            focusFirst();
            break;
        case VK_END:
            focusLast();
            break;
        case VK_PRIOR:
            if (focusedIndex() != scrollOffset()) {
                // Set the selection to the first visible item
                int firstVisibleItem = scrollOffset();
                up(focusedIndex() - firstVisibleItem);
            } else {
                // The first visible item is selected, so move the selection back one page
                up(visibleItems());
            }
            break;
        case VK_NEXT: {
            int lastVisibleItem = scrollOffset() + visibleItems() - 1;
            if (focusedIndex() != lastVisibleItem) {
                // Set the selection to the last visible item
                down(lastVisibleItem - focusedIndex());
            } else {
                // The last visible item is selected, so move the selection forward one page
                down(visibleItems());
            }
            break;
        }
        case VK_TAB:
            ::SendMessage(client()->hostWindow()->platformPageClient(), message, wParam, lParam);
            hide();
            break;
        case VK_ESCAPE:
            hide();
            break;
        default:
            if (isASCIIPrintable(wParam))
                // Send the keydown to the WebView so it can be used for type-to-select.
                // Since we know that the virtual key is ASCII printable, it's OK to convert this to
                // a WM_CHAR message. (We don't want to call TranslateMessage because that will post a
                // WM_CHAR message that will be stolen and redirected to the popup HWND.
                ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, wParam, lParam);
            else
                lResult = 1;
            break;
        }
        break;
    }
    case WM_CHAR: {
        if (!client())
            break;

        lResult = 0;
        int index;
        switch (wParam) {
        case 0x0D:   // Enter/Return
            hide();
            index = focusedIndex();
            ASSERT(index >= 0);
            client()->valueChanged(index);
            break;
        case 0x1B:   // Escape
            hide();
            break;
        case 0x09:   // TAB
        case 0x08:   // Backspace
        case 0x0A:   // Linefeed
        default:     // Character
            lResult = 1;
            break;
        }
        break;
    }
    case WM_MOUSEMOVE: {
        IntPoint mousePoint(MAKEPOINTS(lParam));
        if (scrollbar()) {
            IntRect scrollBarRect = scrollbar()->frameRect();
            if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) {
                // Put the point into coordinates relative to the scroll bar
                mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
                PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y()));
                scrollbar()->mouseMoved(event);
                break;
            }
        }

        BOOL shouldHotTrack = FALSE;
        if (!::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0))
            shouldHotTrack = FALSE;

        RECT bounds;
        GetClientRect(popupHandle(), &bounds);
        if (!::PtInRect(&bounds, mousePoint) && !(wParam & MK_LBUTTON) && client()) {
            // When the mouse is not inside the popup menu and the left button isn't down, just
            // repost the message to the web view.

            // Translate the coordinate.
            translatePoint(lParam, m_popup, client()->hostWindow()->platformPageClient());

            ::PostMessage(m_popup, WM_HOST_WINDOW_MOUSEMOVE, wParam, lParam);
            break;
        }

        if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, mousePoint)) {
            setFocusedIndex(listIndexAtPoint(mousePoint), true);
            m_hoveredIndex = listIndexAtPoint(mousePoint);
        }

        break;
    }
    case WM_LBUTTONDOWN: {
        IntPoint mousePoint(MAKEPOINTS(lParam));
        if (scrollbar()) {
            IntRect scrollBarRect = scrollbar()->frameRect();
            if (scrollBarRect.contains(mousePoint)) {
                // Put the point into coordinates relative to the scroll bar
                mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
                PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y()));
                scrollbar()->mouseDown(event);
                setScrollbarCapturingMouse(true);
                break;
            }
        }

        // If the mouse is inside the window, update the focused index. Otherwise,
        // hide the popup.
        RECT bounds;
        GetClientRect(m_popup, &bounds);
        if (::PtInRect(&bounds, mousePoint)) {
            setFocusedIndex(listIndexAtPoint(mousePoint), true);
            m_hoveredIndex = listIndexAtPoint(mousePoint);
        }
        else
            hide();
        break;
    }
    case WM_LBUTTONUP: {
        IntPoint mousePoint(MAKEPOINTS(lParam));
        if (scrollbar()) {
            IntRect scrollBarRect = scrollbar()->frameRect();
            if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) {
                setScrollbarCapturingMouse(false);
                // Put the point into coordinates relative to the scroll bar
                mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
                PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y()));
                scrollbar()->mouseUp(event);
                // FIXME: This is a hack to work around Scrollbar not invalidating correctly when it doesn't have a parent widget
                RECT r = scrollBarRect;
                ::InvalidateRect(popupHandle(), &r, TRUE);
                break;
            }
        }
        // Only hide the popup if the mouse is inside the popup window.
        RECT bounds;
        GetClientRect(popupHandle(), &bounds);
        if (client() && ::PtInRect(&bounds, mousePoint)) {
            hide();
            int index = m_hoveredIndex;
            if (!client()->itemIsEnabled(index))
                index = client()->selectedIndex();
            if (index >= 0)
                client()->valueChanged(index);
        }
        break;
    }

    case WM_MOUSEWHEEL: {
        if (!scrollbar())
            break;

        int i = 0;
        for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelDelta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) {
            if (wheelDelta() > 0)
                ++i;
            else
                --i;
        }

        ScrollableArea::scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i));
        break;
    }

    case WM_PAINT: {
        PAINTSTRUCT paintInfo;
        ::BeginPaint(popupHandle(), &paintInfo);
        paint(paintInfo.rcPaint, paintInfo.hdc);
        ::EndPaint(popupHandle(), &paintInfo);
        lResult = 0;
        break;
    }
    case WM_PRINTCLIENT:
        paint(clientRect(), (HDC)wParam);
        break;
    case WM_GETOBJECT:
        onGetObject(wParam, lParam, lResult);
        break;
    default:
        lResult = DefWindowProc(hWnd, message, wParam, lParam);
    }

    return lResult;
}
Exemple #29
0
void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom, const CCOcclusionTracker* occlusion)
{
    createTextureUpdaterIfNeeded();

    // Create tiles as needed, expanding a dirty rect to contain all
    // the dirty regions currently being drawn. All dirty tiles that are to be painted
    // get their m_updateRect set to m_dirtyRect and m_dirtyRect cleared. This way if
    // invalidateRect is invoked during prepareToUpdate we don't lose the request.
    IntRect dirtyLayerRect;
    for (int j = top; j <= bottom; ++j) {
        for (int i = left; i <= right; ++i) {
            UpdatableTile* tile = tileAt(i, j);
            if (!tile)
                tile = createTile(i, j);

            // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or mark it for update.
            // If any part of the tile is visible, then we need to paint it so the tile is pushed to the impl thread.
            // This will also avoid painting the tile in the next loop, below.
            if (!idle && occlusion) {
                IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleLayerRect());
                if (occlusion->occluded(this, visibleTileRect))
                    continue;
            }

            // FIXME: Decide if partial update should be allowed based on cost
            // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
            if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost() && layerTreeHost()->requestPartialTextureUpdate())
                tile->m_partialUpdate = true;
            else if (tileNeedsBufferedUpdate(tile) && layerTreeHost())
                layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal());

            if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) {
                // Sets the dirty rect to a full-sized tile with border texels.
                tile->m_dirtyRect = m_tiler->tileRect(tile);
            }

            if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) {
                m_skipsIdlePaint = true;
                if (!idle) {
                    // If the background covers the viewport, always draw this
                    // layer so that checkerboarded tiles will still draw.
                    if (!backgroundCoversViewport())
                        m_skipsDraw = true;
                    m_tiler->reset();
                    m_paintRect = IntRect();
                    m_requestedUpdateTilesRect = IntRect();
                }
                return;
            }

            dirtyLayerRect.unite(tile->m_dirtyRect);
            tile->copyAndClearDirty();
        }
    }

    m_paintRect = dirtyLayerRect;
    if (dirtyLayerRect.isEmpty())
        return;

    // Due to borders, when the paint rect is extended to tile boundaries, it
    // may end up overlapping more tiles than the original content rect. Record
    // the original tiles so we don't upload more tiles than necessary.
    if (!m_paintRect.isEmpty())
        m_requestedUpdateTilesRect = IntRect(left, top, right - left + 1, bottom - top + 1);

    // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
    // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
    // However, we can't free the memory backing the GraphicsContext until the paint finishes,
    // so we grab a local reference here to hold the updater alive until the paint completes.
    RefPtr<LayerTextureUpdater> protector(textureUpdater());
    IntRect paintedOpaqueRect;
    textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &paintedOpaqueRect);
    for (int j = top; j <= bottom; ++j) {
        for (int i = left; i <= right; ++i) {
            UpdatableTile* tile = tileAt(i, j);

            // Tiles are created before prepareToUpdate() is called.
            if (!tile)
                CRASH();

            IntRect tileRect = m_tiler->tileBounds(i, j);

            // Use m_updateRect as copyAndClearDirty above moved the existing dirty rect to m_updateRect if the tile isn't culled.
            const IntRect& dirtyRect = tile->m_updateRect;
            if (dirtyRect.isEmpty())
                continue;

            // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some
            // other part of the tile opaque.
            IntRect tilePaintedRect = intersection(tileRect, m_paintRect);
            IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect);
            if (!tilePaintedRect.isEmpty()) {
                IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRect(), tilePaintedRect);
                bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.contains(paintInsideTileOpaqueRect);
                bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect);

                if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect)
                    tile->setOpaqueRect(tilePaintedOpaqueRect);
            }

            // sourceRect starts as a full-sized tile with border texels included.
            IntRect sourceRect = m_tiler->tileRect(tile);
            sourceRect.intersect(dirtyRect);
            // Paint rect not guaranteed to line up on tile boundaries, so
            // make sure that sourceRect doesn't extend outside of it.
            sourceRect.intersect(m_paintRect);

            tile->m_updateRect = sourceRect;
            if (sourceRect.isEmpty())
                continue;

            tile->texture()->prepareRect(sourceRect);
        }
    }
}
Exemple #30
0
void TiledBackingStore::createTiles()
{
    if (m_contentsFrozen)
        return;
    
    IntRect visibleRect = visibleContentsRect();
    m_previousVisibleRect = visibleRect;

    if (visibleRect.isEmpty())
        return;

    // Resize tiles on edges in case the contents size has changed.
    bool didResizeTiles = resizeEdgeTiles();

    IntRect keepRect = computeKeepRect(visibleRect);
    
    dropTilesOutsideRect(keepRect);
    
    IntRect coverRect = computeCoverRect(visibleRect);
    ASSERT(keepRect.contains(coverRect));
    
    // Search for the tile position closest to the viewport center that does not yet contain a tile. 
    // Which position is considered the closest depends on the tileDistance function.
    double shortestDistance = std::numeric_limits<double>::infinity();
    Vector<Tile::Coordinate> tilesToCreate;
    unsigned requiredTileCount = 0;
    Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location());
    Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(coverRect));
    for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) {
        for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) {
            Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate);
            if (tileAt(currentCoordinate))
                continue;
            ++requiredTileCount;
            // Distance is 0 for all currently visible tiles.
            double distance = tileDistance(visibleRect, currentCoordinate);
            if (distance > shortestDistance)
                continue;
            if (distance < shortestDistance) {
                tilesToCreate.clear();
                shortestDistance = distance;
            }
            tilesToCreate.append(currentCoordinate);
        }
    }
    
    // Now construct the tile(s)
    unsigned tilesToCreateCount = tilesToCreate.size();
    for (unsigned n = 0; n < tilesToCreateCount; ++n) {
        Tile::Coordinate coordinate = tilesToCreate[n];
        setTile(coordinate, m_backend->createTile(this, coordinate));
    }
    requiredTileCount -= tilesToCreateCount;
    
    // Paint the content of the newly created tiles
    if (tilesToCreateCount || didResizeTiles)
        updateTileBuffers();

    // Keep creating tiles until the whole coverRect is covered.
    if (requiredTileCount)
        m_tileCreationTimer->startOneShot(m_tileCreationDelay);
}