TEST_F(ScrollingCoordinatorChromiumTest, touchOverflowScrolling) { registerMockedHttpURLLoad("touch-overflow-scrolling.html"); navigateTo(m_baseURL + "touch-overflow-scrolling.html"); // Verify the properties of the accelerated scrolling element starting from the RenderObject // all the way to the WebLayer. Element* scrollableElement = m_webViewImpl->mainFrameImpl()->frame()->document()->getElementById("scrollable"); ASSERT(scrollableElement); RenderObject* renderer = scrollableElement->renderer(); ASSERT_TRUE(renderer->isBoxModelObject()); ASSERT_TRUE(renderer->hasLayer()); RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); ASSERT_TRUE(layer->usesCompositedScrolling()); ASSERT_TRUE(layer->isComposited()); RenderLayerBacking* layerBacking = layer->backing(); ASSERT_TRUE(layerBacking->hasScrollingLayer()); ASSERT(layerBacking->scrollingContentsLayer()); GraphicsLayerChromium* graphicsLayerChromium = static_cast<GraphicsLayerChromium*>(layerBacking->scrollingContentsLayer()); ASSERT_EQ(layer, graphicsLayerChromium->scrollableArea()); WebLayer* webScrollLayer = static_cast<WebLayer*>(layerBacking->scrollingContentsLayer()->platformLayer()); ASSERT_TRUE(webScrollLayer->scrollable()); }
TEST_F(ScrollingCoordinatorChromiumTest, fastScrollingForFixedPosition) { registerMockedHttpURLLoad("fixed-position.html"); navigateTo(m_baseURL + "fixed-position.html"); Page* page = m_webViewImpl->mainFrameImpl()->frame()->page(); ASSERT_TRUE(page->scrollingCoordinator()->supportsFixedPositionLayers()); // Fixed position should not fall back to main thread scrolling. WebLayer* rootScrollLayer = getRootScrollLayer(); ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread()); // Verify the properties of the fixed position element starting from the RenderObject all the // way to the WebLayer. Element* fixedElement = m_webViewImpl->mainFrameImpl()->frame()->document()->getElementById("fixed"); ASSERT(fixedElement); RenderObject* renderer = fixedElement->renderer(); ASSERT_TRUE(renderer->isBoxModelObject()); ASSERT_TRUE(renderer->hasLayer()); RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); ASSERT_TRUE(layer->isComposited()); RenderLayerBacking* layerBacking = layer->backing(); WebLayer* webLayer = static_cast<WebLayer*>(layerBacking->graphicsLayer()->platformLayer()); ASSERT_TRUE(webLayer->fixedToContainerLayer()); }
WebRenderLayer::WebRenderLayer(RenderLayer* layer) { RenderBoxModelObject* renderer = layer->renderer(); m_renderObjectName = renderer->renderName(); if (Node* node = renderer->node()) { if (node->isElementNode()) { Element* element = toElement(node); m_elementTagName = element->tagName(); m_elementID = element->getIdAttribute(); if (element->isStyledElement() && element->hasClass()) { StyledElement* styledElement = static_cast<StyledElement*>(element); if (size_t classNameCount = styledElement->classNames().size()) { m_elementClassNames = MutableArray::create(); for (size_t i = 0; i < classNameCount; ++i) m_elementClassNames->append(WebString::create(styledElement->classNames()[i]).get()); } } } } m_isReflection = layer->isReflection(); #if USE(ACCELERATED_COMPOSITING) if (layer->isComposited()) { RenderLayerBacking* backing = layer->backing(); m_isClipping = backing->hasClippingLayer(); m_isClipped = backing->hasAncestorClippingLayer(); switch (backing->compositingLayerType()) { case NormalCompositingLayer: m_compositingLayerType = Normal; break; case TiledCompositingLayer: m_compositingLayerType = Tiled; break; case MediaCompositingLayer: m_compositingLayerType = Media; break; case ContainerCompositingLayer: m_compositingLayerType = Container; break; } } else { #endif m_isClipping = false; m_isClipped = false; m_compositingLayerType = None; #if USE(ACCELERATED_COMPOSITING) } #endif m_absoluteBoundingBox = layer->absoluteBoundingBox(); m_negativeZOrderList = createArrayFromLayerList(layer->negZOrderList()); m_normalFlowList = createArrayFromLayerList(layer->normalFlowList()); m_positiveZOrderList = createArrayFromLayerList(layer->posZOrderList()); }
PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString* errorString, RenderLayer* renderLayer) { RenderObject* renderer = &renderLayer->renderer(); RenderLayerBacking* backing = renderLayer->backing(); Node* node = renderer->node(); bool isReflection = renderLayer->isReflection(); bool isGenerated = (isReflection ? renderer->parent() : renderer)->isBeforeOrAfterContent(); bool isAnonymous = renderer->isAnonymous(); if (renderer->isRenderView()) node = &renderer->document(); else if (isReflection && isGenerated) node = renderer->parent()->generatingElement(); else if (isGenerated) node = renderer->generatingNode(); else if (isReflection || isAnonymous) node = renderer->parent()->element(); // Basic set of properties. RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create() .setLayerId(bind(renderLayer)) .setNodeId(idForNode(errorString, node)) .setBounds(buildObjectForIntRect(renderer->absoluteBoundingBoxRect())) .setMemory(backing->backingStoreMemoryEstimate()) .setCompositedBounds(buildObjectForIntRect(enclosingIntRect(backing->compositedBounds()))) .setPaintCount(backing->graphicsLayer()->repaintCount()); if (node && node->shadowHost()) layerObject->setIsInShadowTree(true); if (isReflection) layerObject->setIsReflection(true); if (isGenerated) { if (isReflection) renderer = renderer->parent(); layerObject->setIsGeneratedContent(true); layerObject->setPseudoElementId(bindPseudoElement(toPseudoElement(renderer->node()))); if (renderer->isBeforeContent()) layerObject->setPseudoElement("before"); else if (renderer->isAfterContent()) layerObject->setPseudoElement("after"); } // FIXME: RenderView is now really anonymous but don't tell about it to the frontend before making sure it can handle it. if (isAnonymous && !renderer->isRenderView()) { layerObject->setIsAnonymous(true); if (RenderStyle* style = renderer->style()) { if (style->styleType() == FIRST_LETTER) layerObject->setPseudoElement("first-letter"); else if (style->styleType() == FIRST_LINE) layerObject->setPseudoElement("first-line"); } } return layerObject; }
void VideoLayerChromium::updateContentsIfDirty() { if (!m_contentsDirty) return; RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (!backing || backing->paintingGoesToWindow()) return; ASSERT(drawsContent()); m_skipsDraw = false; VideoFrameChromium* frame = m_provider->getCurrentFrame(); if (!frame) { m_skipsDraw = true; m_provider->putCurrentFrame(frame); return; } m_frameFormat = frame->format(); unsigned textureFormat = determineTextureFormat(frame); if (textureFormat == GraphicsContext3D::INVALID_VALUE) { // FIXME: Implement other paths. notImplemented(); m_skipsDraw = true; m_provider->putCurrentFrame(frame); return; } if (frame->surfaceType() == VideoFrameChromium::TypeTexture) { releaseCurrentFrame(); saveCurrentFrame(frame); m_dirtyRect.setSize(FloatSize()); m_contentsDirty = false; return; } // Allocate textures for planes if they are not allocated already, or // reallocate textures that are the wrong size for the frame. GraphicsContext3D* context = layerRendererContext(); bool texturesAllocated = allocateTexturesIfNeeded(context, frame, textureFormat); if (!texturesAllocated) { m_skipsDraw = true; m_provider->putCurrentFrame(frame); return; } // Update texture planes. for (unsigned plane = 0; plane < frame->planes(); plane++) { ASSERT(frame->requiredTextureSize(plane) == m_textureSizes[plane]); updateTexture(context, m_textures[plane], frame->requiredTextureSize(plane), textureFormat, frame->data(plane)); } m_dirtyRect.setSize(FloatSize()); m_contentsDirty = false; m_provider->putCurrentFrame(frame); }
void LayerChromium::updateContents() { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (backing && !backing->paintingGoesToWindow() && drawsContent()) m_owner->paintGraphicsLayerContents(*m_graphicsContext, IntRect(0, 0, m_bounds.width(), m_bounds.height())); m_contentsDirty = false; }
PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(RenderLayer* renderLayer) { bool isComposited = renderLayer->isComposited(); // Basic set of properties. RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create() .setLayerId(bind(renderLayer)) .setBounds(buildObjectForIntRect(enclosingIntRect(renderLayer->localBoundingBox()))) .setIsComposited(isComposited); // Optional properties for composited layers only. if (isComposited) { RenderLayerBacking* backing = renderLayer->backing(); layerObject->setMemory(backing->backingStoreMemoryEstimate()); layerObject->setCompositedBounds(buildObjectForIntRect(backing->compositedBounds())); layerObject->setPaintCount(backing->graphicsLayer()->repaintCount()); } // Process children layers. RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> > childrenArray = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create(); renderLayer->updateLayerListsIfNeeded(); // Check if we have a reflection layer. if (renderLayer->reflectionLayer()) childrenArray->addItem(buildObjectForLayer(renderLayer->reflectionLayer())); if (renderLayer->isStackingContext()) { if (Vector<RenderLayer*>* negZOrderList = renderLayer->negZOrderList()) { size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) childrenArray->addItem(buildObjectForLayer(negZOrderList->at(i))); } } if (Vector<RenderLayer*>* normalFlowList = renderLayer->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) childrenArray->addItem(buildObjectForLayer(normalFlowList->at(i))); } if (renderLayer->isStackingContext()) { if (Vector<RenderLayer*>* posZOrderList = renderLayer->posZOrderList()) { size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) childrenArray->addItem(buildObjectForLayer(posZOrderList->at(i))); } } layerObject->setChildLayers(childrenArray); return layerObject; }
WebRenderLayer::WebRenderLayer(RenderLayer* layer) { m_renderer = WebRenderObject::create(&layer->renderer()); m_isReflection = layer->isReflection(); #if USE(ACCELERATED_COMPOSITING) if (layer->isComposited()) { RenderLayerBacking* backing = layer->backing(); m_isClipping = backing->hasClippingLayer(); m_isClipped = backing->hasAncestorClippingLayer(); switch (backing->compositingLayerType()) { case NormalCompositingLayer: m_compositingLayerType = Normal; break; case TiledCompositingLayer: m_compositingLayerType = Tiled; break; case MediaCompositingLayer: m_compositingLayerType = Media; break; case ContainerCompositingLayer: m_compositingLayerType = Container; break; } } else { #endif m_isClipping = false; m_isClipped = false; m_compositingLayerType = None; #if USE(ACCELERATED_COMPOSITING) } #endif m_absoluteBoundingBox = layer->absoluteBoundingBox(); m_negativeZOrderList = createArrayFromLayerList(layer->negZOrderList()); m_normalFlowList = createArrayFromLayerList(layer->normalFlowList()); m_positiveZOrderList = createArrayFromLayerList(layer->posZOrderList()); }
static void updateOffsetFromViewportForSelf(RenderLayer* renderLayer) { // These conditions must match the conditions in RenderLayerCompositor::requiresCompositingForPosition. RenderLayerBacking* backing = renderLayer->backing(); if (!backing) return; RenderStyle* style = renderLayer->renderer()->style(); if (!style) return; if (!renderLayer->renderer()->isOutOfFlowPositioned() || renderLayer->renderer()->style()->position() != FixedPosition) return; if (!renderLayer->renderer()->container()->isRenderView()) return; if (!renderLayer->isStackingContext()) return; CoordinatedGraphicsLayer* graphicsLayer = toCoordinatedGraphicsLayer(backing->graphicsLayer()); graphicsLayer->setFixedToViewport(true); }
void ContentLayerChromium::updateContents() { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (!backing || backing->paintingGoesToWindow()) return; ASSERT(drawsContent()); ASSERT(layerRenderer()); void* pixels = 0; IntRect dirtyRect; IntRect updateRect; IntSize requiredTextureSize; IntSize bitmapSize; // FIXME: Remove this test when tiled layers are implemented. if (requiresClippedUpdateRect()) { // A layer with 3D transforms could require an arbitrarily large number // of texels to be repainted, so ignore these layers until tiling is // implemented. if (!drawTransform().isIdentityOrTranslation()) { m_skipsDraw = true; return; } calculateClippedUpdateRect(dirtyRect, m_largeLayerDrawRect); if (!layerRenderer()->checkTextureSize(m_largeLayerDrawRect.size())) { m_skipsDraw = true; return; } // If the portion of the large layer that's visible hasn't changed // then we don't need to update it, _unless_ its contents have changed // in which case we only update the dirty bits. if (m_largeLayerDirtyRect == dirtyRect) { if (!m_dirtyRect.intersects(dirtyRect)) return; dirtyRect.intersect(IntRect(m_dirtyRect)); updateRect = dirtyRect; requiredTextureSize = m_largeLayerDirtyRect.size(); } else { m_largeLayerDirtyRect = dirtyRect; requiredTextureSize = dirtyRect.size(); updateRect = IntRect(IntPoint(0, 0), dirtyRect.size()); } } else { dirtyRect = IntRect(m_dirtyRect); IntRect boundsRect(IntPoint(0, 0), m_bounds); requiredTextureSize = m_bounds; // If the texture needs to be reallocated then we must redraw the entire // contents of the layer. if (requiredTextureSize != m_allocatedTextureSize) dirtyRect = boundsRect; else { // Clip the dirtyRect to the size of the layer to avoid drawing // outside the bounds of the backing texture. dirtyRect.intersect(boundsRect); } updateRect = dirtyRect; } if (dirtyRect.isEmpty()) return; #if PLATFORM(SKIA) const SkBitmap* skiaBitmap = 0; OwnPtr<skia::PlatformCanvas> canvas; OwnPtr<PlatformContextSkia> skiaContext; OwnPtr<GraphicsContext> graphicsContext; canvas.set(new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), false)); skiaContext.set(new PlatformContextSkia(canvas.get())); // This is needed to get text to show up correctly. // FIXME: Does this take us down a very slow text rendering path? skiaContext->setDrawingToImageBuffer(true); graphicsContext.set(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get()))); // Bring the canvas into the coordinate system of the paint rect. canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y())); m_owner->paintGraphicsLayerContents(*graphicsContext, dirtyRect); const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); skiaBitmap = &bitmap; ASSERT(skiaBitmap); SkAutoLockPixels lock(*skiaBitmap); SkBitmap::Config skiaConfig = skiaBitmap->config(); // FIXME: do we need to support more image configurations? if (skiaConfig == SkBitmap::kARGB_8888_Config) { pixels = skiaBitmap->getPixels(); bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); } #elif PLATFORM(CG) Vector<uint8_t> tempVector; int rowBytes = 4 * dirtyRect.width(); tempVector.resize(rowBytes * dirtyRect.height()); memset(tempVector.data(), 0, tempVector.size()); RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); RetainPtr<CGContextRef> contextCG(AdoptCF, CGBitmapContextCreate(tempVector.data(), dirtyRect.width(), dirtyRect.height(), 8, rowBytes, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); CGContextTranslateCTM(contextCG.get(), 0, dirtyRect.height()); CGContextScaleCTM(contextCG.get(), 1, -1); GraphicsContext graphicsContext(contextCG.get()); // Translate the graphics context into the coordinate system of the dirty rect. graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y()); m_owner->paintGraphicsLayerContents(graphicsContext, dirtyRect); pixels = tempVector.data(); bitmapSize = dirtyRect.size(); #else #error "Need to implement for your platform." #endif unsigned textureId = m_contentsTexture; if (!textureId) textureId = layerRenderer()->createLayerTexture(); if (pixels) updateTextureRect(pixels, bitmapSize, requiredTextureSize, updateRect, textureId); }
void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, const CompositingState& compositingState, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer) { // Make the layer compositing if necessary, and set up clipping and content layers. // Note that we can only do work here that is independent of whether the descendant layers // have been processed. computeCompositingRequirements() will already have done the repaint if necessary. RenderLayerBacking* layerBacking = layer->backing(); if (layerBacking) { // The compositing state of all our children has been updated already, so now // we can compute and cache the composited bounds for this layer. layerBacking->updateCompositedBounds(); if (RenderLayer* reflection = layer->reflectionLayer()) { if (reflection->backing()) reflection->backing()->updateCompositedBounds(); } layerBacking->updateGraphicsLayerConfiguration(); layerBacking->updateGraphicsLayerGeometry(); if (!layer->parent()) updateRootLayerPosition(); } // If this layer has backing, then we are collecting its children, otherwise appending // to the compositing child list of an enclosing layer. Vector<GraphicsLayer*> layerChildren; Vector<GraphicsLayer*>& childList = layerBacking ? layerChildren : childLayersOfEnclosingLayer; CompositingState childState = compositingState; if (layer->isComposited()) childState.m_compositingAncestor = layer; #ifndef NDEBUG ++childState.m_depth; #endif // The children of this stacking context don't need to composite, unless there is // a compositing layer among them, so start by assuming false. childState.m_subtreeIsCompositing = false; if (layer->isStackingContext()) { ASSERT(!layer->m_zOrderListsDirty); if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) { size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); rebuildCompositingLayerTree(curLayer, childState, childList); } } // If a negative z-order child is compositing, we get a foreground layer which needs to get parented. if (layerBacking && layerBacking->foregroundLayer()) childList.append(layerBacking->foregroundLayer()); } ASSERT(!layer->m_normalFlowListDirty); if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) { size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); rebuildCompositingLayerTree(curLayer, childState, childList); } } if (layer->isStackingContext()) { if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) { size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); rebuildCompositingLayerTree(curLayer, childState, childList); } } } if (layerBacking) { layerBacking->parentForSublayers()->setChildren(layerChildren); childLayersOfEnclosingLayer.append(layerBacking->childForSuperlayers()); } }
void LayerChromium::updateTextureContents(unsigned int textureId) { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); if (backing && !backing->paintingGoesToWindow()) { void* pixels = 0; IntRect dirtyRect(m_dirtyRect); IntSize requiredTextureSize; IntSize bitmapSize; #if PLATFORM(SKIA) const SkBitmap* skiaBitmap = 0; OwnPtr<skia::PlatformCanvas> canvas; OwnPtr<PlatformContextSkia> skiaContext; OwnPtr<GraphicsContext> graphicsContext; if (drawsContent()) { // Layer contents must be drawn into a canvas. // Clip the dirtyRect to the size of the layer to avoid drawing outside // the bounds of the backing texture. dirtyRect.intersect(IntRect(IntPoint(0, 0), m_bounds)); canvas.set(new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), false)); skiaContext.set(new PlatformContextSkia(canvas.get())); // This is needed to get text to show up correctly. Without it, // GDI renders with zero alpha and the text becomes invisible. // Unfortunately, setting this to true disables cleartype. // FIXME: Does this take us down a very slow text rendering path? skiaContext->setDrawingToImageBuffer(true); graphicsContext.set(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get()))); // Bring the canvas into the coordinate system of the paint rect. canvas->translate(static_cast<SkScalar>(-dirtyRect.x()), static_cast<SkScalar>(-dirtyRect.y())); m_owner->paintGraphicsLayerContents(*graphicsContext, dirtyRect); const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); skiaBitmap = &bitmap; requiredTextureSize = m_bounds; } else { // Layer is a container. // The layer contains an Image. NativeImageSkia* skiaImage = static_cast<NativeImageSkia*>(contents()); skiaBitmap = skiaImage; requiredTextureSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); } ASSERT(skiaBitmap); SkAutoLockPixels lock(*skiaBitmap); SkBitmap::Config skiaConfig = skiaBitmap->config(); // FIXME: do we need to support more image configurations? if (skiaConfig == SkBitmap::kARGB_8888_Config) { pixels = skiaBitmap->getPixels(); bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); } #else #error "Need to implement for your platform." #endif if (pixels) { glBindTexture(GL_TEXTURE_2D, textureId); // If the texture id or size changed since last time then we need to tell GL // to re-allocate a texture. if (m_allocatedTextureId != textureId || requiredTextureSize != m_allocatedTextureSize) { ASSERT(bitmapSize == requiredTextureSize); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, requiredTextureSize.width(), requiredTextureSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); m_allocatedTextureId = textureId; m_allocatedTextureSize = requiredTextureSize; } else { ASSERT(dirtyRect.width() <= m_allocatedTextureSize.width() && dirtyRect.height() <= m_allocatedTextureSize.height()); ASSERT(dirtyRect.width() == bitmapSize.width() && dirtyRect.height() == bitmapSize.height()); glTexSubImage2D(GL_TEXTURE_2D, 0, dirtyRect.x(), dirtyRect.y(), dirtyRect.width(), dirtyRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels); } } } m_contentsDirty = false; m_dirtyRect.setSize(FloatSize()); }