Exemplo n.º 1
0
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());
}
Exemplo n.º 2
0
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());
}
Exemplo n.º 3
0
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());
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
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());
}
Exemplo n.º 9
0
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);
}
Exemplo n.º 10
0
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());
    }
}
Exemplo n.º 12
0
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());
}