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; }
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; }
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; }
FloatQuad mapQuad(const FloatQuad& quad) const { if (!m_transform) { FloatQuad q = quad; q.move(m_offset); return q; } return m_transform->mapQuad(quad); }
FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderLayerModelObject* container) const { FloatQuad result; if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) { result = rect; result.move(m_accumulatedOffset); } else { TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect); mapToContainer(transformState, container); result = transformState.lastPlanarQuad(); } return result; }
FloatQuad TransformState::mappedQuad(bool* wasClamped) const { if (wasClamped) *wasClamped = false; FloatQuad quad = m_lastPlanarQuad; quad.move((m_direction == ApplyTransformDirection) ? m_accumulatedOffset : -m_accumulatedOffset); if (!m_accumulatedTransform) return quad; if (m_direction == ApplyTransformDirection) return m_accumulatedTransform->mapQuad(quad); return m_accumulatedTransform->inverse().projectQuad(quad, wasClamped); }
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; }
static void buildRendererHighlight(RenderObject* renderer, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight, InspectorOverlay::CoordinateSystem coordinateSystem) { Frame* containingFrame = renderer->document().frame(); if (!containingFrame) return; highlight->setDataFromConfig(highlightConfig); FrameView* containingView = containingFrame->view(); FrameView* mainView = containingFrame->page()->mainFrame().view(); // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads(). bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot(); if (isSVGRenderer) { highlight->type = HighlightTypeRects; renderer->absoluteQuads(highlight->quads); for (size_t i = 0; i < highlight->quads.size(); ++i) contentsQuadToCoordinateSystem(mainView, containingView, highlight->quads[i], coordinateSystem); } else if (renderer->isBox() || renderer->isRenderInline()) { LayoutRect contentBox; LayoutRect paddingBox; LayoutRect borderBox; LayoutRect marginBox; if (renderer->isBox()) { RenderBox* renderBox = toRenderBox(renderer); LayoutBoxExtent margins(renderBox->marginTop(), renderBox->marginRight(), renderBox->marginBottom(), renderBox->marginLeft()); if (!renderBox->isOutOfFlowPositioned() && region) { RenderBox::LogicalExtentComputedValues computedValues; renderBox->computeLogicalWidthInRegion(computedValues, region); margins.mutableLogicalLeft(renderBox->style().writingMode()) = computedValues.m_margins.m_start; margins.mutableLogicalRight(renderBox->style().writingMode()) = computedValues.m_margins.m_end; } paddingBox = renderBox->clientBoxRectInRegion(region); contentBox = LayoutRect(paddingBox.x() + renderBox->paddingLeft(), paddingBox.y() + renderBox->paddingTop(), paddingBox.width() - renderBox->paddingLeft() - renderBox->paddingRight(), paddingBox.height() - renderBox->paddingTop() - renderBox->paddingBottom()); borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(), paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom()); marginBox = LayoutRect(borderBox.x() - margins.left(), borderBox.y() - margins.top(), borderBox.width() + margins.left() + margins.right(), borderBox.height() + margins.top() + margins.bottom()); } else { RenderInline* renderInline = toRenderInline(renderer); // RenderInline's bounding box includes paddings and borders, excludes margins. borderBox = renderInline->linesBoundingBox(); paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(), borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom()); contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(), paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom()); // Ignore marginTop and marginBottom for inlines. marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(), borderBox.width() + renderInline->horizontalMarginExtent(), borderBox.height()); } FloatQuad absContentQuad; FloatQuad absPaddingQuad; FloatQuad absBorderQuad; FloatQuad absMarginQuad; if (region) { RenderFlowThread* flowThread = region->flowThread(); // Figure out the quads in the space of the RenderFlowThread. absContentQuad = renderer->localToContainerQuad(FloatRect(contentBox), flowThread); absPaddingQuad = renderer->localToContainerQuad(FloatRect(paddingBox), flowThread); absBorderQuad = renderer->localToContainerQuad(FloatRect(borderBox), flowThread); absMarginQuad = renderer->localToContainerQuad(FloatRect(marginBox), flowThread); // Move the quad relative to the space of the current region. LayoutRect flippedRegionRect(region->flowThreadPortionRect()); flowThread->flipForWritingMode(flippedRegionRect); FloatSize delta = region->contentBoxRect().location() - flippedRegionRect.location(); absContentQuad.move(delta); absPaddingQuad.move(delta); absBorderQuad.move(delta); absMarginQuad.move(delta); // Resolve the absolute quads starting from the current region. absContentQuad = region->localToAbsoluteQuad(absContentQuad); absPaddingQuad = region->localToAbsoluteQuad(absPaddingQuad); absBorderQuad = region->localToAbsoluteQuad(absBorderQuad); absMarginQuad = region->localToAbsoluteQuad(absMarginQuad); } else { absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox)); absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox)); absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox)); absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox)); } contentsQuadToCoordinateSystem(mainView, containingView, absContentQuad, coordinateSystem); contentsQuadToCoordinateSystem(mainView, containingView, absPaddingQuad, coordinateSystem); contentsQuadToCoordinateSystem(mainView, containingView, absBorderQuad, coordinateSystem); contentsQuadToCoordinateSystem(mainView, containingView, absMarginQuad, coordinateSystem); highlight->type = HighlightTypeNode; highlight->quads.append(absMarginQuad); highlight->quads.append(absBorderQuad); highlight->quads.append(absPaddingQuad); highlight->quads.append(absContentQuad); } }
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; }