void GraphicsLayerClutter::setNeedsDisplayInRect(const FloatRect& r) { if (!drawsContent()) return; FloatRect rect(r); FloatRect layerBounds(FloatPoint(), m_size); rect.intersect(layerBounds); if (rect.isEmpty()) return; const size_t maxDirtyRects = 32; for (size_t i = 0; i < m_dirtyRects.size(); ++i) { if (m_dirtyRects[i].contains(rect)) return; } if (m_dirtyRects.size() < maxDirtyRects) m_dirtyRects.append(rect); else m_dirtyRects[0].unite(rect); noteLayerPropertyChanged(DirtyRectsChanged); }
IntRect ContentLayerChromium::visibleLayerRect(const IntRect& targetSurfaceRect) { if (targetSurfaceRect.isEmpty()) return targetSurfaceRect; const IntRect layerBoundRect = layerBounds(); const TransformationMatrix transform = tilingTransform(); // Is this layer fully contained within the target surface? IntRect layerInSurfaceSpace = transform.mapRect(layerBoundRect); if (targetSurfaceRect.contains(layerInSurfaceSpace)) return layerBoundRect; // If the layer doesn't fill up the entire surface, then find the part of // the surface rect where the layer could be visible. This avoids trying to // project surface rect points that are behind the projection point. IntRect minimalSurfaceRect = targetSurfaceRect; minimalSurfaceRect.intersect(layerInSurfaceSpace); // Project the corners of the target surface rect into the layer space. // This bounding rectangle may be larger than it needs to be (being // axis-aligned), but is a reasonable filter on the space to consider. // Non-invertible transforms will create an empty rect here. const TransformationMatrix surfaceToLayer = transform.inverse(); IntRect layerRect = surfaceToLayer.projectQuad(FloatQuad(FloatRect(minimalSurfaceRect))).enclosingBoundingBox(); layerRect.intersect(layerBoundRect); return layerRect; }
void ContentLayerChromium::paintContentsIfDirty(const IntRect& targetSurfaceRect) { ASSERT(drawsContent()); ASSERT(layerRenderer()); updateLayerSize(layerBounds().size()); IntRect layerRect = visibleLayerRect(targetSurfaceRect); if (layerRect.isEmpty()) return; IntRect dirty = enclosingIntRect(m_dirtyRect); dirty.intersect(layerBounds()); m_tiler->invalidateRect(dirty); m_tiler->prepareToUpdate(layerRect); m_dirtyRect = FloatRect(); }
LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { LayoutRect localExposeRect(box().absoluteToLocalQuad(FloatQuad(FloatRect(rect)), UseTransforms).boundingBox()); LayoutRect layerBounds(0, 0, box().clientWidth(), box().clientHeight()); LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect, alignX, alignY); IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() + toIntSize(roundedIntRect(r).location())); if (clampedScrollOffset == adjustedScrollOffset()) return rect; IntSize oldScrollOffset = adjustedScrollOffset(); scrollToOffset(clampedScrollOffset); IntSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset; localExposeRect.move(-scrollOffsetDifference); return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeRect)), UseTransforms).boundingBox()); }
bool GraphicsLayerAndroid::repaint() { LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", this, gPaused, m_needsRepaint, m_haveContents); if (!gPaused && m_haveContents && m_needsRepaint && !m_image) { // with SkPicture, we request the entire layer's content. IntRect layerBounds(0, 0, m_size.width(), m_size.height()); RenderLayer* layer = renderLayerFromClient(m_client); if (!layer) return false; if (m_foregroundLayer) { PaintingPhase phase(this); // Paint the background into a separate context. phase.set(GraphicsLayerPaintBackground); if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; m_contentLayer->checkTextPresence(); // Construct the foreground layer and draw. RenderBox* box = layer->renderBox(); int outline = box->view()->maximalOutlineSize(); IntRect contentsRect(0, 0, box->borderLeft() + box->borderRight() + layer->scrollWidth(), box->borderTop() + box->borderBottom() + layer->scrollHeight()); contentsRect.inflate(outline); // Update the foreground layer size. m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height()); // Paint everything else into the main recording canvas. phase.clear(GraphicsLayerPaintBackground); // Paint at 0,0. IntSize scroll = layer->scrolledContentOffset(); layer->scrollToOffset(0, 0); // At this point, it doesn't matter if painting failed. (void) paintContext(m_foregroundLayer->recordContext(), contentsRect); m_foregroundLayer->checkTextPresence(); layer->scrollToOffset(scroll.width(), scroll.height()); // Construct the clip layer for masking the contents. IntRect clip = layer->renderer()->absoluteBoundingBoxRect(); // absoluteBoundingBoxRect does not include the outline so we need // to offset the position. int x = box->borderLeft() + outline; int y = box->borderTop() + outline; int width = clip.width() - box->borderLeft() - box->borderRight(); int height = clip.height() - box->borderTop() - box->borderBottom(); m_foregroundClipLayer->setPosition(x, y); m_foregroundClipLayer->setSize(width, height); // Need to offset the foreground layer by the clip layer in order // for the contents to be in the correct position. m_foregroundLayer->setPosition(-x, -y); // Set the scrollable bounds of the layer. m_foregroundLayer->setScrollLimits(-x, -y, m_size.width(), m_size.height()); // Invalidate the entire layer for now, as webkit will only send the // setNeedsDisplayInRect() for the visible (clipped) scrollable area, // offsetting the invals by the scroll position would not be enough. // TODO: have webkit send us invals even for non visible area SkRegion region; region.setRect(0, 0, contentsRect.width(), contentsRect.height()); m_foregroundLayer->markAsDirty(region); m_foregroundLayer->needsRepaint(); } else { // If there is no contents clip, we can draw everything into one // picture. if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; m_contentLayer->checkTextPresence(); // Check for a scrollable iframe and report the scrolling // limits based on the view size. if (m_contentLayer->contentIsScrollable()) { FrameView* view = layer->renderer()->frame()->view(); static_cast<ScrollableLayerAndroid*>(m_contentLayer)->setScrollLimits( m_position.x(), m_position.y(), view->layoutWidth(), view->layoutHeight()); } } LOG("(%x) repaint() on (%.2f,%.2f) contentlayer(%.2f,%.2f,%.2f,%.2f)paintGraphicsLayer called!", this, m_size.width(), m_size.height(), m_contentLayer->getPosition().fX, m_contentLayer->getPosition().fY, m_contentLayer->getSize().width(), m_contentLayer->getSize().height()); m_contentLayer->markAsDirty(m_dirtyRegion); m_dirtyRegion.setEmpty(); m_contentLayer->needsRepaint(); m_needsRepaint = false; return true; } if (m_needsRepaint && m_image && m_newImage) { // We need to tell the GL thread that we will need to repaint the // texture. Only do so if we effectively have a new image! m_contentLayer->markAsDirty(m_dirtyRegion); m_dirtyRegion.setEmpty(); m_contentLayer->needsRepaint(); m_newImage = false; m_needsRepaint = false; return true; } return false; }
void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { #if DEBUG_DISPLAY_LIST properties().debugOutputProperties(handler.level() + 1); #endif if (properties().getLeft() != 0 || properties().getTop() != 0) { renderer.translate(properties().getLeft(), properties().getTop()); } if (properties().getStaticMatrix()) { renderer.concatMatrix(*properties().getStaticMatrix()); } else if (properties().getAnimationMatrix()) { renderer.concatMatrix(*properties().getAnimationMatrix()); } if (properties().hasTransformMatrix()) { if (properties().isTransformTranslateOnly()) { renderer.translate(properties().getTranslationX(), properties().getTranslationY()); } else { renderer.concatMatrix(*properties().getTransformMatrix()); } } const bool isLayer = properties().effectiveLayerType() != LayerType::None; int clipFlags = properties().getClippingFlags(); if (properties().getAlpha() < 1) { if (isLayer) { clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer } if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) { // simply scale rendering content's alpha renderer.scaleAlpha(properties().getAlpha()); } else { // savelayer needed to create an offscreen buffer Rect layerBounds(0, 0, getWidth(), getHeight()); if (clipFlags) { properties().getClippingRectForFlags(clipFlags, &layerBounds); clipFlags = 0; // all clipping done by savelayer } SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom, (int) (properties().getAlpha() * 255), SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) { // pretend alpha always causes savelayer to warn about // performance problem affecting old versions ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(), static_cast<int>(getWidth()), static_cast<int>(getHeight())); } } if (clipFlags) { Rect clipRect; properties().getClippingRectForFlags(clipFlags, &clipRect); ClipRectOp* op = new (handler.allocator()) ClipRectOp( clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, SkRegion::kIntersect_Op); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } // TODO: support nesting round rect clips if (mProperties.getRevealClip().willClip()) { Rect bounds; mProperties.getRevealClip().getBounds(&bounds); renderer.setClippingRoundRect(handler.allocator(), bounds, mProperties.getRevealClip().getRadius()); } else if (mProperties.getOutline().willClip()) { renderer.setClippingOutline(handler.allocator(), &(mProperties.getOutline())); } }