void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLayer(const LayerType* layer) { ASSERT(!m_stack.isEmpty()); ASSERT(layer->targetRenderSurface() == m_stack.last().surface); if (m_stack.isEmpty()) return; if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1) return; IntRect scissorInTarget = layerScissorRectInTargetSurface(layer); if (layerTransformsToTargetKnown(layer)) m_stack.last().occlusionInTarget.unite(computeOcclusionBehindLayer<LayerType>(layer, contentToTargetSurfaceTransform<LayerType>(layer), scissorInTarget, m_usePaintTracking)); // We must clip the occlusion within the layer's scissorInTarget within screen space as well. If the scissor rect can't be moved to screen space and // remain rectilinear, then we don't add any occlusion in screen space. if (layerTransformsToScreenKnown(layer)) { TransformationMatrix targetToScreenTransform = m_stack.last().surface->screenSpaceTransform(); FloatQuad scissorInScreenQuad = targetToScreenTransform.mapQuad(FloatQuad(FloatRect(scissorInTarget))); if (!scissorInScreenQuad.isRectilinear()) return; IntRect scissorInScreenRect = intersection(m_scissorRectInScreenSpace, enclosedIntRect(CCMathUtil::mapClippedRect(targetToScreenTransform, FloatRect(scissorInTarget)))); m_stack.last().occlusionInScreen.unite(computeOcclusionBehindLayer<LayerType>(layer, contentToScreenSpaceTransform<LayerType>(layer), scissorInScreenRect, m_usePaintTracking)); } }
void LayerRendererChromium::drawTexturedQuad(const TransformationMatrix& drawMatrix, float width, float height, float opacity, const FloatQuad& quad, int matrixLocation, int alphaLocation, int quadLocation) { static float glMatrix[16]; TransformationMatrix renderMatrix = drawMatrix; // Apply a scaling factor to size the quad from 1x1 to its intended size. renderMatrix.scale3d(width, height, 1); // Apply the projection matrix before sending the transform over to the shader. toGLMatrix(&glMatrix[0], m_projectionMatrix * renderMatrix); GLC(m_context, m_context->uniformMatrix4fv(matrixLocation, false, &glMatrix[0], 1)); if (quadLocation != -1) { float point[8]; point[0] = quad.p1().x(); point[1] = quad.p1().y(); point[2] = quad.p2().x(); point[3] = quad.p2().y(); point[4] = quad.p3().x(); point[5] = quad.p3().y(); point[6] = quad.p4().x(); point[7] = quad.p4().y(); GLC(m_context, m_context->uniform2fv(quadLocation, point, 4)); } if (alphaLocation != -1) GLC(m_context, m_context->uniform1f(alphaLocation, opacity)); GLC(m_context, m_context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0)); }
FloatQuad LayoutGeometryMap::mapToAncestor(const FloatRect& rect, const LayoutBoxModelObject* ancestor) const { FloatQuad result; if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!ancestor || (m_mapping.size() && ancestor == m_mapping[0].m_layoutObject))) { result = rect; result.move(m_accumulatedOffset); } else { TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect); mapToAncestor(transformState, ancestor); result = transformState.lastPlanarQuad(); } #if ENABLE(ASSERT) if (m_mapping.size() > 0) { const LayoutObject* lastLayoutObject = m_mapping.last().m_layoutObject; FloatRect layoutObjectMappedResult = lastLayoutObject->localToAncestorQuad(rect, ancestor, m_mapCoordinatesFlags).boundingBox(); // Inspector creates layoutObjects with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>. // Taking FloatQuad bounds avoids spurious assertions because of that. ASSERT(enclosingIntRect(layoutObjectMappedResult) == enclosingIntRect(result.boundingBox()) || layoutObjectMappedResult.mayNotHaveExactIntRectRepresentation() || result.boundingBox().mayNotHaveExactIntRectRepresentation()); } #endif return result; }
static inline Region computeOcclusionBehindLayer(const LayerType* layer, const TransformationMatrix& transform, const IntRect& scissorRect, bool usePaintTracking) { Region opaqueRegion; bool clipped; FloatQuad unoccludedQuad = CCMathUtil::mapQuad(transform, FloatQuad(layer->visibleLayerRect()), clipped); bool isPaintedAxisAligned = unoccludedQuad.isRectilinear(); // FIXME: Find a rect interior to each transformed quad. if (clipped || !isPaintedAxisAligned) return opaqueRegion; if (layer->opaque()) opaqueRegion = enclosedIntRect(unoccludedQuad.boundingBox()); else if (usePaintTracking && transform.isIdentity()) opaqueRegion = layer->visibleContentOpaqueRegion(); else if (usePaintTracking) { Region contentRegion = layer->visibleContentOpaqueRegion(); Vector<IntRect> contentRects = contentRegion.rects(); // We verify that the possible bounds of this region are not clipped above, so we can use mapRect() safely here. for (size_t i = 0; i < contentRects.size(); ++i) opaqueRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(contentRects[i])))); } opaqueRegion.intersect(scissorRect); return opaqueRegion; }
void PainterOpenVG::intersectClipRect(const FloatRect& rect) { ASSERT(m_state); m_surface->makeCurrent(); if (m_state->surfaceTransformationMatrix.isIdentity()) { // No transformation required, skip all the complex stuff. intersectScissorRect(rect); return; } // Check if the actual destination rectangle is still rectilinear (can be // represented as FloatRect) so we could apply scissoring instead of // (potentially more expensive) path clipping. Note that scissoring is not // subject to transformations, so we need to do the transformation to // surface coordinates by ourselves. FloatQuad effectiveScissorQuad = m_state->surfaceTransformationMatrix.mapQuad(FloatQuad(rect)); if (effectiveScissorQuad.isRectilinear()) intersectScissorRect(effectiveScissorQuad.boundingBox()); else { // The transformed scissorRect cannot be represented as FloatRect // anymore, so we need to perform masking instead. Not yet implemented. notImplemented(); } }
void RenderLayerModelObject::addChildFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset) const { for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling()) { if (current->isText() || current->isListMarker()) continue; if (!current->isBox()) { current->addFocusRingRects(rects, additionalOffset); continue; } RenderBox* box = toRenderBox(current); if (!box->hasLayer()) { box->addFocusRingRects(rects, additionalOffset + box->locationOffset()); continue; } Vector<LayoutRect> layerFocusRingRects; box->addFocusRingRects(layerFocusRingRects, LayoutPoint()); for (size_t i = 0; i < layerFocusRingRects.size(); ++i) { FloatQuad quadInBox = box->localToContainerQuad(FloatQuad(layerFocusRingRects[i]), this); LayoutRect rect = LayoutRect(quadInBox.boundingBox()); if (!rect.isEmpty()) { rect.moveBy(additionalOffset); rects.append(rect); } } } }
bool SVGInlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), lineLayoutItem().style()->pointerEvents()); bool isVisible = lineLayoutItem().style()->visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox || (hitRules.canHitStroke && (lineLayoutItem().style()->svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (lineLayoutItem().style()->svgStyle().hasFill() || !hitRules.requireFill))) { LayoutPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); LayoutRect rect(boxOrigin, size()); if (locationInContainer.intersects(rect)) { LineLayoutSVGInlineText lineLayoutItem = LineLayoutSVGInlineText(this->lineLayoutItem()); ASSERT(lineLayoutItem.scalingFactor()); float baseline = lineLayoutItem.scaledFont().fontMetrics().floatAscent() / lineLayoutItem.scalingFactor(); FloatPoint floatLocation = FloatPoint(locationInContainer.point()); for (const SVGTextFragment& fragment : m_textFragments) { FloatQuad fragmentQuad = fragment.boundingQuad(baseline); if (fragmentQuad.containsPoint(floatLocation)) { lineLayoutItem.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (!result.addNodeToListBasedTestResult(lineLayoutItem.node(), locationInContainer, rect)) return true; } } } } } return false; }
FloatQuad LayoutGeometryMap::mapToContainer(const FloatRect& rect, const LayoutBoxModelObject* container) const { FloatQuad result; if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_layoutObject))) { result = rect; result.move(m_accumulatedOffset); } else { TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect); mapToContainer(transformState, container); result = transformState.lastPlanarQuad(); } #if ENABLE(ASSERT) if (m_mapping.size() > 0) { const LayoutObject* lastLayoutObject = m_mapping.last().m_layoutObject; const DeprecatedPaintLayer* layer = lastLayoutObject->enclosingLayer(); // Bounds for invisible layers are intentionally not calculated, and are // therefore not necessarily expected to be correct here. This is ok, // because they will be recomputed if the layer becomes visible. if (!layer->subtreeIsInvisible() && lastLayoutObject->style()->visibility() == VISIBLE) { FloatRect layoutObjectMappedResult = lastLayoutObject->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox(); // Inspector creates layoutObjects with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>. // Taking FloatQuad bounds avoids spurious assertions because of that. ASSERT(enclosingIntRect(layoutObjectMappedResult) == enclosingIntRect(result.boundingBox())); } } #endif return result; }
// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. // FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends // on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. IntRect RenderSVGModelObject::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer, IntPoint*) const { IntRect box = enclosingIntRect(repaintRectInLocalCoordinates()); adjustRectForOutlineAndShadow(box); FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); return containerRelativeQuad.enclosingBoundingBox(); }
// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. // FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends // on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const { LayoutRect box = enclosingLayoutRect(repaintRectInLocalCoordinates()); adjustRectForOutlineAndShadow(box); FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); return containerRelativeQuad.enclosingBoundingBox(); }
// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. // FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends // on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const { LayoutRect box = enclosingLayoutRect(repaintRectInLocalCoordinates()); adjustRectForOutlineAndShadow(box); FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); return LayoutRect(snapRectToDevicePixels(LayoutRect(containerRelativeQuad.boundingBox()), document().deviceScaleFactor())); }
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; }
static void addQuadToPath(const FloatQuad& quad, Path& path) { // FIXME: Make this create rounded quad-paths, just like the axis-aligned case. path.moveTo(quad.p1()); path.addLineTo(quad.p2()); path.addLineTo(quad.p3()); path.addLineTo(quad.p4()); path.closeSubpath(); }
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; }
static PassRefPtr<InspectorArray> buildArrayForQuad(const FloatQuad& quad) { RefPtr<InspectorArray> array = InspectorArray::create(); array->pushObject(buildObjectForPoint(quad.p1())); array->pushObject(buildObjectForPoint(quad.p2())); array->pushObject(buildObjectForPoint(quad.p3())); array->pushObject(buildObjectForPoint(quad.p4())); return array.release(); }
void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad) { const FrameView& frameView = renderer.view().frameView(); FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect)); quad->setP1(frameView.contentsToRootView(roundedIntPoint(absolute.p1()))); quad->setP2(frameView.contentsToRootView(roundedIntPoint(absolute.p2()))); quad->setP3(frameView.contentsToRootView(roundedIntPoint(absolute.p3()))); quad->setP4(frameView.contentsToRootView(roundedIntPoint(absolute.p4()))); }
HitTestLocation::HitTestLocation(const FloatPoint& point, const FloatQuad& quad) : m_transformedPoint(point) , m_transformedRect(quad) , m_isRectBased(true) { m_point = flooredLayoutPoint(point); m_boundingBox = enclosingIntRect(quad.boundingBox()); m_isRectilinear = quad.isRectilinear(); }
static void localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad) { LocalFrame* frame = renderer.frame(); FrameView* view = frame->view(); FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect)); quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1()))); quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2()))); quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3()))); quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4()))); }
FloatQuad mapQuad(const FloatQuad& quad) const { if (!m_transform) { FloatQuad q = quad; q.move(m_offset); return q; } return m_transform->mapQuad(quad); }
IntRect AccessibilitySliderThumb::elementRect() const { if (!m_parentSlider->renderer()) return IntRect(); IntRect intRect = toRenderSlider(m_parentSlider->renderer())->thumbRect(); FloatQuad floatQuad = m_parentSlider->renderer()->localToAbsoluteQuad(FloatRect(intRect)); return floatQuad.enclosingBoundingBox(); }
static Path quadToPath(const FloatQuad& quad) { Path quadPath; quadPath.moveTo(quad.p1()); quadPath.addLineTo(quad.p2()); quadPath.addLineTo(quad.p3()); quadPath.addLineTo(quad.p4()); quadPath.closeSubpath(); return quadPath; }
IntRect CCRenderSurface::computeDeviceBoundingBox(LayerRendererChromium* layerRenderer, const TransformationMatrix& drawTransform) const { TransformationMatrix contentsDeviceTransform = computeDeviceTransform(layerRenderer, drawTransform); // Can only draw surface if device matrix is invertible. if (!contentsDeviceTransform.isInvertible()) return IntRect(); FloatQuad deviceQuad = contentsDeviceTransform.mapQuad(layerRenderer->sharedGeometryQuad()); return enclosingIntRect(deviceQuad.boundingBox()); }
FloatRect TransformationMatrix::mapRect(const FloatRect& r) const { if (isIdentityOrTranslation()) { FloatRect mappedRect(r); mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); return mappedRect; } FloatQuad resultQuad = mapQuad(FloatQuad(r)); return resultQuad.boundingBox(); }
static IntRect screenRectOfContents(Element* element) { ASSERT(element); if (element->renderer() && element->renderer()->hasLayer() && element->renderer()->enclosingLayer()->isComposited()) { FloatQuad contentsBox = static_cast<FloatRect>(element->renderer()->enclosingLayer()->backing()->contentsBox()); contentsBox = element->renderer()->localToAbsoluteQuad(contentsBox); return element->renderer()->view().frameView().contentsToScreen(contentsBox.enclosingBoundingBox()); } return element->screenRect(); }
bool RoundedRect::intersectsQuad(const FloatQuad& quad) const { FloatRect rect(m_rect); if (!quad.intersectsRect(rect)) return false; const IntSize& topLeft = m_radii.topLeft(); if (!topLeft.isEmpty()) { FloatRect rect(m_rect.x(), m_rect.y(), topLeft.width(), topLeft.height()); if (quad.intersectsRect(rect)) { FloatPoint center(m_rect.x() + topLeft.width(), m_rect.y() + topLeft.height()); FloatSize size(topLeft.width(), topLeft.height()); if (!quad.intersectsEllipse(center, size)) return false; } } const IntSize& topRight = m_radii.topRight(); if (!topRight.isEmpty()) { FloatRect rect(m_rect.maxX() - topRight.width(), m_rect.y(), topRight.width(), topRight.height()); if (quad.intersectsRect(rect)) { FloatPoint center(m_rect.maxX() - topRight.width(), m_rect.y() + topRight.height()); FloatSize size(topRight.width(), topRight.height()); if (!quad.intersectsEllipse(center, size)) return false; } } const IntSize& bottomLeft = m_radii.bottomLeft(); if (!bottomLeft.isEmpty()) { FloatRect rect(m_rect.x(), m_rect.maxY() - bottomLeft.height(), bottomLeft.width(), bottomLeft.height()); if (quad.intersectsRect(rect)) { FloatPoint center(m_rect.x() + bottomLeft.width(), m_rect.maxY() - bottomLeft.height()); FloatSize size(bottomLeft.width(), bottomLeft.height()); if (!quad.intersectsEllipse(center, size)) return false; } } const IntSize& bottomRight = m_radii.bottomRight(); if (!bottomRight.isEmpty()) { FloatRect rect(m_rect.maxX() - bottomRight.width(), m_rect.maxY() - bottomRight.height(), bottomRight.width(), bottomRight.height()); if (quad.intersectsRect(rect)) { FloatPoint center(m_rect.maxX() - bottomRight.width(), m_rect.maxY() - bottomRight.height()); FloatSize size(bottomRight.width(), bottomRight.height()); if (!quad.intersectsEllipse(center, size)) return false; } } return true; }
bool SVGInlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), getLineLayoutItem().style()->pointerEvents()); bool isVisible = getLineLayoutItem().style()->visibility() == EVisibility::Visible; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox || (hitRules.canHitStroke && (getLineLayoutItem().style()->svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (getLineLayoutItem().style()->svgStyle().hasFill() || !hitRules.requireFill))) { LayoutRect rect(topLeft(), LayoutSize(logicalWidth(), logicalHeight())); rect.moveBy(accumulatedOffset); if (locationInContainer.intersects(rect)) { LineLayoutSVGInlineText lineLayoutItem = LineLayoutSVGInlineText(this->getLineLayoutItem()); const SimpleFontData* fontData = lineLayoutItem.scaledFont().primaryFont(); DCHECK(fontData); if (!fontData) return false; DCHECK(lineLayoutItem.scalingFactor()); float baseline = fontData->getFontMetrics().floatAscent() / lineLayoutItem.scalingFactor(); FloatPoint floatLocation = FloatPoint(locationInContainer.point()); for (const SVGTextFragment& fragment : m_textFragments) { FloatQuad fragmentQuad = fragment.boundingQuad(baseline); if (fragmentQuad.containsPoint(floatLocation)) { lineLayoutItem.updateHitTestResult( result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (result.addNodeToListBasedTestResult(lineLayoutItem.node(), locationInContainer, rect) == StopHitTesting) return true; } } } } } return false; }
void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* targetSurface) { if (layer->renderSurface() && layer->renderSurface() != targetSurface) { layer->renderSurface()->draw(layer->getDrawRect()); return; } if (!layer->drawsContent()) return; if (layer->bounds().isEmpty()) { layer->unreserveContentsTexture(); return; } setScissorToRect(layer->scissorRect()); IntRect targetSurfaceRect = m_currentRenderSurface ? m_currentRenderSurface->contentRect() : m_defaultRenderSurface->contentRect(); IntRect scissorRect = layer->scissorRect(); if (!scissorRect.isEmpty()) targetSurfaceRect.intersect(scissorRect); // Check if the layer falls within the visible bounds of the page. IntRect layerRect = layer->getDrawRect(); bool isLayerVisible = targetSurfaceRect.intersects(layerRect); if (!isLayerVisible) { layer->unreserveContentsTexture(); return; } // FIXME: Need to take into account the commulative render surface transforms all the way from // the default render surface in order to determine visibility. TransformationMatrix combinedDrawMatrix = (layer->targetRenderSurface() ? layer->targetRenderSurface()->drawTransform().multiply(layer->drawTransform()) : layer->drawTransform()); if (!layer->doubleSided()) { FloatRect layerRect(FloatPoint(0, 0), FloatSize(layer->bounds())); FloatQuad mappedLayer = combinedDrawMatrix.mapQuad(FloatQuad(layerRect)); FloatSize horizontalDir = mappedLayer.p2() - mappedLayer.p1(); FloatSize verticalDir = mappedLayer.p4() - mappedLayer.p1(); FloatPoint3D xAxis(horizontalDir.width(), horizontalDir.height(), 0); FloatPoint3D yAxis(verticalDir.width(), verticalDir.height(), 0); FloatPoint3D zAxis = xAxis.cross(yAxis); if (zAxis.z() < 0) { layer->unreserveContentsTexture(); return; } } layer->draw(targetSurfaceRect); // Draw the debug border if there is one. layer->drawDebugBorder(); }
static IntRect screenRectOfContents(Element* element) { ASSERT(element); #if USE(ACCELERATED_COMPOSITING) if (element->renderer() && element->renderer()->hasLayer() && element->renderer()->enclosingLayer()->isComposited()) { FloatQuad contentsBox = static_cast<FloatRect>(element->renderer()->enclosingLayer()->backing()->contentsBox()); contentsBox = element->renderer()->localToAbsoluteQuad(contentsBox, SnapOffsetForTransforms); return element->renderer()->view()->frameView()->contentsToScreen(contentsBox.enclosingBoundingBox()); } #endif return element->screenRect(); }
FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const { FloatQuad projectedQuad; projectedQuad.setP1(projectPoint(q.p1())); projectedQuad.setP2(projectPoint(q.p2())); projectedQuad.setP3(projectPoint(q.p3())); projectedQuad.setP4(projectPoint(q.p4())); return projectedQuad; }
static PassRefPtr<InspectorArray> createQuad(const FloatQuad& quad) { RefPtr<InspectorArray> array = InspectorArray::create(); array->pushDouble(quad.p1().x()); array->pushDouble(quad.p1().y()); array->pushDouble(quad.p2().x()); array->pushDouble(quad.p2().y()); array->pushDouble(quad.p3().x()); array->pushDouble(quad.p3().y()); array->pushDouble(quad.p4().x()); array->pushDouble(quad.p4().y()); return array.release(); }