Path path() const { Path path; buildPathFromByteStream(m_rawStream, path); path.translate(toFloatSize(m_offset)); return path; }
bool VisualViewport::magnifyScaleAroundAnchor(float magnifyDelta, const FloatPoint& anchor) { const float oldPageScale = scale(); const float newPageScale = frameHost().chromeClient().clampPageScaleFactorToLimits( magnifyDelta * oldPageScale); if (newPageScale == oldPageScale) return false; if (!mainFrame() || !mainFrame()->view()) return false; // Keep the center-of-pinch anchor in a stable position over the course // of the magnify. FloatPoint anchorAtOldScale = anchor.scaledBy(1.f / oldPageScale); FloatPoint anchorAtNewScale = anchor.scaledBy(1.f / newPageScale); FloatSize anchorDelta = anchorAtOldScale - anchorAtNewScale; // First try to use the anchor's delta to scroll the FrameView. FloatSize anchorDeltaUnusedByScroll = anchorDelta; if (!frameHost().settings().invertViewportScrollOrder()) { FrameView* view = mainFrame()->view(); DoublePoint oldPosition = view->scrollPositionDouble(); view->scrollBy(DoubleSize(anchorDelta.width(), anchorDelta.height()), UserScroll); DoublePoint newPosition = view->scrollPositionDouble(); anchorDeltaUnusedByScroll -= toFloatSize(newPosition - oldPosition); } // Manually bubble any remaining anchor delta up to the visual viewport. FloatPoint newLocation(location() + anchorDeltaUnusedByScroll); setScaleAndLocation(newPageScale, newLocation); return true; }
bool LinkHighlight::computeHighlightLayerPathAndPosition(const LayoutBoxModelObject* paintInvalidationContainer) { if (!m_node || !m_node->layoutObject() || !m_currentGraphicsLayer) return false; ASSERT(paintInvalidationContainer); // FIXME: This is defensive code to avoid crashes such as those described in // crbug.com/440887. This should be cleaned up once we fix the root cause of // of the paint invalidation container not being composited. if (!paintInvalidationContainer->layer()->compositedDeprecatedPaintLayerMapping() && !paintInvalidationContainer->layer()->groupedMapping()) return false; // Get quads for node in absolute coordinates. Vector<FloatQuad> quads; computeQuads(*m_node, quads); ASSERT(quads.size()); Path newPath; FloatPoint positionAdjustForCompositedScrolling = IntPoint(m_currentGraphicsLayer->offsetFromRenderer()); for (size_t quadIndex = 0; quadIndex < quads.size(); ++quadIndex) { FloatQuad absoluteQuad = quads[quadIndex]; // FIXME: this hack should not be necessary. It's a consequence of the fact that composited layers for scrolling are represented // differently in Blink than other composited layers. if (paintInvalidationContainer->layer()->needsCompositedScrolling() && m_node->layoutObject() != paintInvalidationContainer) absoluteQuad.move(-positionAdjustForCompositedScrolling.x(), -positionAdjustForCompositedScrolling.y()); // Transform node quads in target absolute coords to local coordinates in the compositor layer. FloatQuad transformedQuad; convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->layoutObject(), paintInvalidationContainer, transformedQuad); // FIXME: for now, we'll only use rounded paths if we have a single node quad. The reason for this is that // we may sometimes get a chain of adjacent boxes (e.g. for text nodes) which end up looking like sausage // links: these should ideally be merged into a single rect before creating the path, but that's // another CL. if (quads.size() == 1 && transformedQuad.isRectilinear() && !m_owningWebViewImpl->settingsImpl()->mockGestureTapHighlightsEnabled()) { FloatSize rectRoundingRadii(3, 3); newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRadii); } else addQuadToPath(transformedQuad, newPath); } FloatRect boundingRect = newPath.boundingRect(); newPath.translate(-toFloatSize(boundingRect.location())); bool pathHasChanged = !(newPath == m_path); if (pathHasChanged) { m_path = newPath; m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size()); } m_contentLayer->layer()->setPosition(boundingRect.location()); return pathHasChanged; }
bool LinkHighlightImpl::computeHighlightLayerPathAndPosition(const LayoutBoxModelObject& paintInvalidationContainer) { if (!m_node || !m_node->layoutObject() || !m_currentGraphicsLayer) return false; // FIXME: This is defensive code to avoid crashes such as those described in // crbug.com/440887. This should be cleaned up once we fix the root cause of // of the paint invalidation container not being composited. if (!paintInvalidationContainer.layer()->compositedLayerMapping() && !paintInvalidationContainer.layer()->groupedMapping()) return false; // Get quads for node in absolute coordinates. Vector<FloatQuad> quads; computeQuads(*m_node, quads); DCHECK(quads.size()); Path newPath; for (size_t quadIndex = 0; quadIndex < quads.size(); ++quadIndex) { FloatQuad absoluteQuad = quads[quadIndex]; // Scrolling content layers have the same offset from layout object as the non-scrolling layers. Thus we need // to adjust for their scroll offset. if (m_isScrollingGraphicsLayer) { DoubleSize adjustedScrollOffset = paintInvalidationContainer.layer()->getScrollableArea()->adjustedScrollOffset(); absoluteQuad.move(adjustedScrollOffset.width(), adjustedScrollOffset.height()); } // Transform node quads in target absolute coords to local coordinates in the compositor layer. FloatQuad transformedQuad; convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->layoutObject(), paintInvalidationContainer, transformedQuad); // FIXME: for now, we'll only use rounded paths if we have a single node quad. The reason for this is that // we may sometimes get a chain of adjacent boxes (e.g. for text nodes) which end up looking like sausage // links: these should ideally be merged into a single rect before creating the path, but that's // another CL. if (quads.size() == 1 && transformedQuad.isRectilinear() && !m_owningWebViewImpl->settingsImpl()->mockGestureTapHighlightsEnabled()) { FloatSize rectRoundingRadii(3, 3); newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRadii); } else { addQuadToPath(transformedQuad, newPath); } } FloatRect boundingRect = newPath.boundingRect(); newPath.translate(-toFloatSize(boundingRect.location())); bool pathHasChanged = !(newPath == m_path); if (pathHasChanged) { m_path = newPath; m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size()); } m_contentLayer->layer()->setPosition(boundingRect.location()); return pathHasChanged; }
bool LinkHighlight::computeHighlightLayerPathAndPosition(RenderLayer* compositingLayer) { if (!m_node || !m_node->renderer() || !m_currentGraphicsLayer) return false; ASSERT(compositingLayer); // Get quads for node in absolute coordinates. Vector<FloatQuad> quads; computeQuads(m_node.get(), quads); ASSERT(quads.size()); // Adjust for offset between target graphics layer and the node's renderer. FloatPoint positionAdjust = IntPoint(m_currentGraphicsLayer->offsetFromRenderer()); Path newPath; for (size_t quadIndex = 0; quadIndex < quads.size(); ++quadIndex) { FloatQuad absoluteQuad = quads[quadIndex]; absoluteQuad.move(-positionAdjust.x(), -positionAdjust.y()); // Transform node quads in target absolute coords to local coordinates in the compositor layer. FloatQuad transformedQuad; convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->renderer(), compositingLayer->renderer(), transformedQuad); // FIXME: for now, we'll only use rounded paths if we have a single node quad. The reason for this is that // we may sometimes get a chain of adjacent boxes (e.g. for text nodes) which end up looking like sausage // links: these should ideally be merged into a single rect before creating the path, but that's // another CL. if (quads.size() == 1 && transformedQuad.isRectilinear()) { FloatSize rectRoundingRadii(3, 3); newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRadii); } else addQuadToPath(transformedQuad, newPath); } FloatRect boundingRect = newPath.boundingRect(); newPath.translate(-toFloatSize(boundingRect.location())); bool pathHasChanged = !(newPath == m_path); if (pathHasChanged) { m_path = newPath; m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size()); } m_contentLayer->layer()->setPosition(boundingRect.location()); return pathHasChanged; }
void ScrollableArea::scrollPositionChanged(const DoublePoint& position, ScrollType scrollType) { TRACE_EVENT0("blink", "ScrollableArea::scrollPositionChanged"); DoublePoint oldPosition = scrollPositionDouble(); DoublePoint truncatedPosition = shouldUseIntegerScrollOffset() ? flooredIntPoint(position) : position; // Tell the derived class to scroll its contents. setScrollOffset(truncatedPosition, scrollType); Scrollbar* verticalScrollbar = this->verticalScrollbar(); // Tell the scrollbars to update their thumb postions. if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { horizontalScrollbar->offsetDidChange(); if (horizontalScrollbar->isOverlayScrollbar() && !hasLayerForHorizontalScrollbar()) { if (!verticalScrollbar) horizontalScrollbar->invalidate(); else { // If there is both a horizontalScrollbar and a verticalScrollbar, // then we must also invalidate the corner between them. IntRect boundsAndCorner = horizontalScrollbar->boundsRect(); boundsAndCorner.setWidth(boundsAndCorner.width() + verticalScrollbar->width()); horizontalScrollbar->invalidateRect(boundsAndCorner); } } } if (verticalScrollbar) { verticalScrollbar->offsetDidChange(); if (verticalScrollbar->isOverlayScrollbar() && !hasLayerForVerticalScrollbar()) verticalScrollbar->invalidate(); } if (scrollPositionDouble() != oldPosition) { // FIXME: Pass in DoubleSize. crbug.com/414283. scrollAnimator()->notifyContentAreaScrolled(toFloatSize(scrollPositionDouble() - oldPosition)); } scrollAnimator()->setCurrentPosition(toFloatPoint(position)); }
Path HTMLAreaElement::computePath(RenderObject* obj) const { if (!obj) return Path(); // FIXME: This doesn't work correctly with transforms. FloatPoint absPos = obj->localToAbsolute(); // Default should default to the size of the containing object. LayoutSize size = m_lastSize; if (m_shape == Default) size = obj->absoluteClippedOverflowRect().size(); Path p = getRegion(size); float zoomFactor = obj->style()->effectiveZoom(); if (zoomFactor != 1.0f) { AffineTransform zoomTransform; zoomTransform.scale(zoomFactor); p.transform(zoomTransform); } p.translate(toFloatSize(absPos)); return p; }
void RootFrameViewport::updateScrollAnimator() { scrollAnimator().setCurrentOffset( toFloatSize(scrollOffsetFromScrollAnimators())); }
Path PathUtilities::pathWithShrinkWrappedRects(const Vector<FloatRect>& rects, float radius) { Path path; if (rects.isEmpty()) return path; if (rects.size() > 20) { path.addRoundedRect(unionRect(rects), FloatSize(radius, radius)); return path; } Vector<FloatRect> sortedRects = rects; std::sort(sortedRects.begin(), sortedRects.end(), [](FloatRect a, FloatRect b) { return b.y() > a.y(); }); FloatPointGraph graph; Vector<FloatPointGraph::Polygon> rectPolygons; rectPolygons.reserveInitialCapacity(sortedRects.size()); for (auto& rect : sortedRects) { bool isContained = false; for (auto& otherRect : sortedRects) { if (&rect == &otherRect) continue; if (otherRect.contains(rect)) { isContained = true; break; } } if (!isContained) rectPolygons.append(edgesForRect(rect, graph)); } Vector<FloatPointGraph::Polygon> polys = unitePolygons(rectPolygons, graph); if (polys.isEmpty()) { path.addRoundedRect(unionRect(sortedRects), FloatSize(radius, radius)); return path; } for (auto& poly : polys) { for (unsigned i = 0; i < poly.size(); i++) { FloatPointGraph::Edge& toEdge = poly[i]; // Connect the first edge to the last. FloatPointGraph::Edge& fromEdge = (i > 0) ? poly[i - 1] : poly[poly.size() - 1]; FloatPoint fromEdgeVec = toFloatPoint(*fromEdge.second - *fromEdge.first); FloatPoint toEdgeVec = toFloatPoint(*toEdge.second - *toEdge.first); // Clamp the radius to no more than half the length of either adjacent edge, // because we want a smooth curve and don't want unequal radii. float clampedRadius = std::min(radius, fabsf(fromEdgeVec.x() ? fromEdgeVec.x() : fromEdgeVec.y()) / 2); clampedRadius = std::min(clampedRadius, fabsf(toEdgeVec.x() ? toEdgeVec.x() : toEdgeVec.y()) / 2); FloatPoint fromEdgeNorm = fromEdgeVec; fromEdgeNorm.normalize(); FloatPoint toEdgeNorm = toEdgeVec; toEdgeNorm.normalize(); // Project the radius along the incoming and outgoing edge. FloatSize fromOffset = clampedRadius * toFloatSize(fromEdgeNorm); FloatSize toOffset = clampedRadius * toFloatSize(toEdgeNorm); if (!i) path.moveTo(*fromEdge.second - fromOffset); else path.addLineTo(*fromEdge.second - fromOffset); path.addArcTo(*fromEdge.second, *toEdge.first + toOffset, clampedRadius); } path.closeSubpath(); } return path; }
void SVGPathBuilder::emitSegment(const PathSegmentData& segment) { switch (segment.command) { case PathSegClosePath: emitClose(); break; case PathSegMoveToAbs: emitMoveTo( segment.targetPoint); break; case PathSegMoveToRel: emitMoveTo( m_currentPoint + segment.targetPoint); break; case PathSegLineToAbs: emitLineTo( segment.targetPoint); break; case PathSegLineToRel: emitLineTo( m_currentPoint + segment.targetPoint); break; case PathSegLineToHorizontalAbs: emitLineTo( FloatPoint(segment.targetPoint.x(), m_currentPoint.y())); break; case PathSegLineToHorizontalRel: emitLineTo( m_currentPoint + FloatSize(segment.targetPoint.x(), 0)); break; case PathSegLineToVerticalAbs: emitLineTo( FloatPoint(m_currentPoint.x(), segment.targetPoint.y())); break; case PathSegLineToVerticalRel: emitLineTo( m_currentPoint + FloatSize(0, segment.targetPoint.y())); break; case PathSegCurveToQuadraticAbs: emitQuadTo( segment.point1, segment.targetPoint); break; case PathSegCurveToQuadraticRel: emitQuadTo( m_currentPoint + segment.point1, m_currentPoint + segment.targetPoint); break; case PathSegCurveToQuadraticSmoothAbs: emitSmoothQuadTo( segment.targetPoint); break; case PathSegCurveToQuadraticSmoothRel: emitSmoothQuadTo( m_currentPoint + segment.targetPoint); break; case PathSegCurveToCubicAbs: emitCubicTo( segment.point1, segment.point2, segment.targetPoint); break; case PathSegCurveToCubicRel: emitCubicTo( m_currentPoint + segment.point1, m_currentPoint + segment.point2, m_currentPoint + segment.targetPoint); break; case PathSegCurveToCubicSmoothAbs: emitSmoothCubicTo( segment.point2, segment.targetPoint); break; case PathSegCurveToCubicSmoothRel: emitSmoothCubicTo( m_currentPoint + segment.point2, m_currentPoint + segment.targetPoint); break; case PathSegArcAbs: emitArcTo( segment.targetPoint, toFloatSize(segment.arcRadii()), segment.arcAngle(), segment.largeArcFlag(), segment.sweepFlag()); break; case PathSegArcRel: emitArcTo( m_currentPoint + segment.targetPoint, toFloatSize(segment.arcRadii()), segment.arcAngle(), segment.largeArcFlag(), segment.sweepFlag()); break; default: ASSERT_NOT_REACHED(); } m_lastCommand = segment.command; }
FloatSize ScrollingTreeFrameScrollingNode::viewToContentsOffset(const FloatPoint& scrollOffset) const { return toFloatSize(scrollOffset) - toFloatSize(scrollOrigin()) - FloatSize(0, headerHeight() + topContentInset()); }
bool LinkHighlight::computeHighlightLayerPathAndPosition(RenderLayer* compositingLayer) { if (!m_node || !m_node->renderer()) return false; ASSERT(compositingLayer); // Get quads for node in absolute coordinates. Vector<FloatQuad> quads; m_node->renderer()->absoluteQuads(quads); ASSERT(quads.size()); FloatRect positionAdjust; if (!m_usingNonCompositedContentHost) { const RenderStyle* style = m_node->renderer()->style(); // If we have a box shadow, and are non-relative, then must manually adjust // for its size. if (const ShadowData* shadow = style->boxShadow()) { int outlineSize = m_node->renderer()->outlineStyleForRepaint()->outlineSize(); shadow->adjustRectForShadow(positionAdjust, outlineSize); } // If absolute or fixed, need to subtract out our fixed positioning. // FIXME: should we use RenderLayer::staticBlockPosition() here instead? // Perhaps consider this if out-of-flow elements cause further problems. if (m_node->renderer()->isOutOfFlowPositioned()) { FloatPoint delta(style->left().getFloatValue(), style->top().getFloatValue()); positionAdjust.moveBy(delta); } } Path newPath; for (unsigned quadIndex = 0; quadIndex < quads.size(); ++quadIndex) { FloatQuad localQuad = m_node->renderer()->absoluteToLocalQuad(quads[quadIndex], UseTransforms); localQuad.move(-positionAdjust.location().x(), -positionAdjust.location().y()); FloatQuad absoluteQuad = m_node->renderer()->localToAbsoluteQuad(localQuad, UseTransforms); // Transform node quads in target absolute coords to local coordinates in the compositor layer. FloatQuad transformedQuad; convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->renderer(), compositingLayer->renderer(), transformedQuad); // FIXME: for now, we'll only use rounded paths if we have a single node quad. The reason for this is that // we may sometimes get a chain of adjacent boxes (e.g. for text nodes) which end up looking like sausage // links: these should ideally be merged into a single rect before creating the path, but that's // another CL. if (quads.size() == 1 && transformedQuad.isRectilinear()) { FloatSize rectRoundingRadii(3, 3); newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRadii); } else addQuadToPath(transformedQuad, newPath); } FloatRect boundingRect = newPath.boundingRect(); newPath.translate(-toFloatSize(boundingRect.location())); bool pathHasChanged = !(newPath == m_path); if (pathHasChanged) { m_path = newPath; m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size()); } m_contentLayer->layer()->setPosition(boundingRect.location()); return pathHasChanged; }