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 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 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(); } }
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(); }
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; }
void CCRenderSurface::drawLayer(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform, int contentsTextureId) { TransformationMatrix deviceMatrix = computeDeviceTransform(layerRenderer, drawTransform); // Can only draw surface if device matrix is invertible. if (!deviceMatrix.isInvertible()) return; // Draw the background texture if there is one. if (m_backgroundTexture && m_backgroundTexture->isReserved()) copyTextureToFramebuffer(layerRenderer, m_backgroundTexture->textureId(), m_contentRect.size(), drawTransform); FloatQuad quad = deviceMatrix.mapQuad(layerRenderer->sharedGeometryQuad()); CCLayerQuad deviceRect = CCLayerQuad(FloatQuad(quad.boundingBox())); CCLayerQuad layerQuad = CCLayerQuad(quad); // Use anti-aliasing programs only when necessary. bool useAA = (!quad.isRectilinear() || !quad.boundingBox().isExpressibleAsIntRect()); if (useAA) { deviceRect.inflateAntiAliasingDistance(); layerQuad.inflateAntiAliasingDistance(); } bool useMask = false; if (maskLayer && maskLayer->drawsContent()) if (!maskLayer->bounds().isEmpty()) useMask = true; // FIXME: pass in backgroundTextureId and blend the background in with this draw instead of having a separate drawBackground() pass. if (useMask) { if (useAA) { const LayerRendererChromium::RenderSurfaceMaskProgramAA* program = layerRenderer->renderSurfaceMaskProgramAA(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, program->fragmentShader().maskSamplerLocation(), program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation()); } else { const LayerRendererChromium::RenderSurfaceMaskProgram* program = layerRenderer->renderSurfaceMaskProgram(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, program->fragmentShader().maskSamplerLocation(), -1, -1); } } else { if (useAA) { const LayerRendererChromium::RenderSurfaceProgramAA* program = layerRenderer->renderSurfaceProgramAA(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, -1, program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation()); } else { const LayerRendererChromium::RenderSurfaceProgram* program = layerRenderer->renderSurfaceProgram(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, -1, -1, -1); } } }
void CCRenderSurface::drawLayer(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform) { TransformationMatrix renderMatrix = drawTransform; // Apply a scaling factor to size the quad from 1x1 to its intended size. renderMatrix.scale3d(m_contentRect.width(), m_contentRect.height(), 1); TransformationMatrix deviceMatrix = TransformationMatrix(layerRenderer->windowMatrix() * layerRenderer->projectionMatrix() * renderMatrix).to2dTransform(); // Can only draw surface if device matrix is invertible. if (!deviceMatrix.isInvertible()) return; FloatQuad quad = deviceMatrix.mapQuad(layerRenderer->sharedGeometryQuad()); CCLayerQuad layerQuad = CCLayerQuad(quad); #if defined(OS_CHROMEOS) // FIXME: Disable anti-aliasing to workaround broken driver. bool useAA = false; #else // Use anti-aliasing programs only when necessary. bool useAA = (!quad.isRectilinear() || !quad.boundingBox().isExpressibleAsIntRect()); #endif if (useAA) layerQuad.inflateAntiAliasingDistance(); bool useMask = false; if (maskLayer && maskLayer->drawsContent()) if (!maskLayer->bounds().isEmpty()) useMask = true; if (useMask) { if (useAA) { const MaskProgramAA* program = layerRenderer->renderSurfaceMaskProgramAA(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, layerQuad, program, program->fragmentShader().maskSamplerLocation(), program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation()); } else { const MaskProgram* program = layerRenderer->renderSurfaceMaskProgram(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, layerQuad, program, program->fragmentShader().maskSamplerLocation(), -1, -1); } } else { if (useAA) { const ProgramAA* program = layerRenderer->renderSurfaceProgramAA(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, layerQuad, program, -1, program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation()); } else { const Program* program = layerRenderer->renderSurfaceProgram(); drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, layerQuad, program, -1, -1, -1); } } }
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; }
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); }
static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surface, const Region& region, const TransformationMatrix& transform) { // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then // apply |transform| to each rect within |region| in order to transform the entire Region. bool clipped; FloatQuad transformedBoundsQuad = CCMathUtil::mapQuad(transform, FloatQuad(region.bounds()), clipped); // FIXME: Find a rect interior to each transformed quad. if (clipped || !transformedBoundsQuad.isRectilinear()) return Region(); Region transformedRegion; Vector<IntRect> rects = region.rects(); // Clipping has been verified above, so mapRect will give correct results. for (size_t i = 0; i < rects.size(); ++i) transformedRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(rects[i])))); return transformedRegion; }
static inline Region computeOcclusionBehindLayer(const LayerType* layer, const TransformationMatrix& transform, bool usePaintTracking) { Region opaqueRegion; FloatQuad unoccludedQuad = transform.mapQuad(FloatQuad(layer->visibleLayerRect())); bool isPaintedAxisAligned = unoccludedQuad.isRectilinear(); if (!isPaintedAxisAligned) return opaqueRegion; if (layer->opaque()) opaqueRegion = enclosedIntRect(unoccludedQuad.boundingBox()); else if (usePaintTracking && transform.isIdentity()) opaqueRegion = layer->opaqueContentsRegion(); else if (usePaintTracking) { Region contentRegion = layer->opaqueContentsRegion(); Vector<IntRect> contentRects = contentRegion.rects(); for (size_t i = 0; i < contentRects.size(); ++i) opaqueRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(contentRects[i])))); } return opaqueRegion; }
static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surface, const Region& region, const TransformationMatrix& transform) { // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then // apply |transform| to each rect within |region| in order to transform the entire Region. IntRect bounds = region.bounds(); FloatRect centeredBounds(-bounds.width() / 2.0, -bounds.height() / 2.0, bounds.width(), bounds.height()); FloatQuad transformedBoundsQuad = transform.mapQuad(FloatQuad(centeredBounds)); if (!transformedBoundsQuad.isRectilinear()) return Region(); Region transformedRegion; IntRect surfaceBounds = surface->contentRect(); Vector<IntRect> rects = region.rects(); Vector<IntRect>::const_iterator end = rects.end(); for (Vector<IntRect>::const_iterator i = rects.begin(); i != end; ++i) { FloatRect centeredOriginRect(-i->width() / 2.0 + i->x() - surfaceBounds.x(), -i->height() / 2.0 + i->y() - surfaceBounds.y(), i->width(), i->height()); FloatRect transformedRect = transform.mapRect(FloatRect(centeredOriginRect)); transformedRegion.unite(enclosedIntRect(transformedRect)); } return transformedRegion; }
void CCTiledLayerImpl::appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuadsData) { const IntRect& contentRect = visibleContentRect(); if (!m_tiler || m_tiler->hasEmptyBounds() || contentRect.isEmpty()) return; CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState()); appendDebugBorderQuad(quadSink, sharedQuadState, appendQuadsData); int left, top, right, bottom; m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom); if (hasDebugBorders()) { for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { DrawableTile* tile = tileAt(i, j); IntRect tileRect = m_tiler->tileBounds(i, j); SkColor borderColor; if (m_skipsDraw || !tile || !tile->resourceId()) borderColor = SkColorSetARGB(debugTileBorderAlpha, debugTileBorderMissingTileColorRed, debugTileBorderMissingTileColorGreen, debugTileBorderMissingTileColorBlue); else borderColor = SkColorSetARGB(debugTileBorderAlpha, debugTileBorderColorRed, debugTileBorderColorGreen, debugTileBorderColorBlue); quadSink.append(CCDebugBorderDrawQuad::create(sharedQuadState, tileRect, borderColor, debugTileBorderWidth).PassAs<CCDrawQuad>(), appendQuadsData); } } } if (m_skipsDraw) return; for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { DrawableTile* tile = tileAt(i, j); IntRect tileRect = m_tiler->tileBounds(i, j); IntRect displayRect = tileRect; tileRect.intersect(contentRect); // Skip empty tiles. if (tileRect.isEmpty()) continue; if (!tile || !tile->resourceId()) { if (drawCheckerboardForMissingTiles()) { SkColor defaultColor = SkColorSetRGB(defaultCheckerboardColorRed, defaultCheckerboardColorGreen, defaultCheckerboardColorBlue); SkColor evictedColor = SkColorSetRGB(debugTileEvictedCheckerboardColorRed, debugTileEvictedCheckerboardColorGreen, debugTileEvictedCheckerboardColorBlue); SkColor invalidatedColor = SkColorSetRGB(debugTileInvalidatedCheckerboardColorRed, debugTileEvictedCheckerboardColorGreen, debugTileEvictedCheckerboardColorBlue); SkColor checkerColor; if (hasDebugBorders()) checkerColor = tile ? invalidatedColor : evictedColor; else checkerColor = defaultColor; appendQuadsData.hadMissingTiles |= quadSink.append(CCCheckerboardDrawQuad::create(sharedQuadState, tileRect, checkerColor).PassAs<CCDrawQuad>(), appendQuadsData); } else appendQuadsData.hadMissingTiles |= quadSink.append(CCSolidColorDrawQuad::create(sharedQuadState, tileRect, backgroundColor()).PassAs<CCDrawQuad>(), appendQuadsData); continue; } IntRect tileOpaqueRect = tile->opaqueRect(); tileOpaqueRect.intersect(contentRect); // Keep track of how the top left has moved, so the texture can be // offset the same amount. IntSize displayOffset = tileRect.minXMinYCorner() - displayRect.minXMinYCorner(); IntPoint textureOffset = m_tiler->textureOffset(i, j) + displayOffset; float tileWidth = static_cast<float>(m_tiler->tileSize().width()); float tileHeight = static_cast<float>(m_tiler->tileSize().height()); IntSize textureSize(tileWidth, tileHeight); bool clipped = false; FloatQuad visibleContentInTargetQuad = CCMathUtil::mapQuad(drawTransform(), FloatQuad(visibleContentRect()), clipped); bool isAxisAlignedInTarget = !clipped && visibleContentInTargetQuad.isRectilinear(); bool useAA = m_tiler->hasBorderTexels() && !isAxisAlignedInTarget; bool leftEdgeAA = !i && useAA; bool topEdgeAA = !j && useAA; bool rightEdgeAA = i == m_tiler->numTilesX() - 1 && useAA; bool bottomEdgeAA = j == m_tiler->numTilesY() - 1 && useAA; const GC3Dint textureFilter = m_tiler->hasBorderTexels() ? GraphicsContext3D::LINEAR : GraphicsContext3D::NEAREST; quadSink.append(CCTileDrawQuad::create(sharedQuadState, tileRect, tileOpaqueRect, tile->resourceId(), textureOffset, textureSize, textureFilter, contentsSwizzled(), leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA).PassAs<CCDrawQuad>(), appendQuadsData); } } }
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; }