Esempio n. 1
0
void Surface::addLayer(LayerAndroid* layer, const TransformationMatrix& transform)
{
    m_layers.append(layer);
    SkSafeRef(layer);

    m_needsTexture |= layer->needsTexture();
    m_hasText |= layer->hasText();

    // add this layer's size to the surface's area
    // TODO: handle scale/3d transform mapping
    IntRect rect = enclosingIntRect(layer->fullContentAreaMapped());

    if (layer->needsTexture()) {
        if (m_fullContentArea.isEmpty()) {
            m_drawTransform = transform;
            m_drawTransform.translate3d(-rect.x(), -rect.y(), 0);
            m_fullContentArea = rect;
        } else
            m_fullContentArea.unite(rect);
        ALOGV("Surf %p adding LA %p, size " INT_RECT_FORMAT
              " now fullContentArea " INT_RECT_FORMAT,
              this, layer, INT_RECT_ARGS(rect), INT_RECT_ARGS(m_fullContentArea));
    }

    if (isBase())
        m_background = static_cast<BaseLayerAndroid*>(layer)->getBackgroundColor();
}
Esempio n. 2
0
bool Surface::blitFromContents(Tile* tile)
{
    if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content())
        return false;
    LayerContent* content = getFirstLayer()->content();
    // Extract the dirty rect from the region. Note that this is *NOT* constrained
    // to this tile
    IntRect dirtyRect = tile->dirtyArea().getBounds();
    IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(),
                               tile->y() * TilesManager::tileHeight(),
                               TilesManager::tileWidth(),
                               TilesManager::tileHeight());
    FloatRect tileRectInDoc = tileRect;
    tileRectInDoc.scale(1 / tile->scale());
    dirtyRect.intersect(enclosingIntRect(tileRectInDoc));
    PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect);
    if (!prerenderedInval || prerenderedInval->bitmap.isNull())
        return false;
    SkBitmap sourceBitmap = prerenderedInval->bitmap;
    // Calculate the screen rect that is dirty, then intersect it with the
    // tile's screen rect so that we end up with the pixels we need to blit
    FloatRect screenDirty = dirtyRect;
    screenDirty.scale(tile->scale());
    IntRect enclosingScreenDirty = enclosingIntRect(screenDirty);
    enclosingScreenDirty.intersect(tileRect);
    if (enclosingScreenDirty.isEmpty())
        return false;
    // Make sure the screen area we want to blit is contained by the
    // prerendered screen area
    if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) {
        ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain "
              "enclosingScreenDirty " INT_RECT_FORMAT,
              INT_RECT_ARGS(prerenderedInval->screenArea),
              INT_RECT_ARGS(enclosingScreenDirty));
        return false;
    }
    IntPoint origin = prerenderedInval->screenArea.location();
    SkBitmap subset;
    subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(),
                     enclosingScreenDirty.height());
    subset.allocPixels();

    int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y();
    int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x();
    if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset))
        return false;
    // Now upload
    SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(),
                           enclosingScreenDirty.y() - tileRect.y(),
                           enclosingScreenDirty.width(),
                           enclosingScreenDirty.height());
    GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId,
                                     subset, textureInval);
    tile->onBlitUpdate();
    return true;
}
Esempio n. 3
0
void PicturePile::appendToPile(const IntRect& inval, const IntRect& originalInval)
{
    ALOGV("Adding inval " INT_RECT_FORMAT " for original inval " INT_RECT_FORMAT,
            INT_RECT_ARGS(inval), INT_RECT_ARGS(originalInval));
    // Remove any entries this obscures
    for (int i = (int) m_pile.size() - 1; i >= 0; i--) {
        if (inval.contains(m_pile[i].area))
            m_pile.remove(i);
    }
    PictureContainer container(inval);
    if (ENABLE_PRERENDERED_INVALS) {
        container.prerendered = PrerenderedInval::create(originalInval.isEmpty()
                                                         ? inval : originalInval);
    }
    m_pile.append(container);
}
Esempio n. 4
0
void PicturePile::updatePicture(PicturePainter* painter, PictureContainer& pc)
{
    /* The ref counting here is a bit unusual. What happens is begin/end recording
     * will ref/unref the recording canvas. However, 'canvas' might be pointing
     * at an SkNWayCanvas instead of the recording canvas, which needs to be
     * unref'd. Thus what we do is ref the recording canvas so that we can
     * always unref whatever canvas we have at the end.
     */
    TRACE_METHOD();
    SkPicture* picture = new SkPicture();
    SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(),
            SkPicture::kUsePathBoundsForClip_RecordingFlag);
    SkSafeRef(canvas);
    canvas->translate(-pc.area.x(), -pc.area.y());
    IntRect drawArea = pc.area;
    if (pc.prerendered.get()) {
        SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get());
        if (!prerender) {
            ALOGV("Failed to create prerendered for " INT_RECT_FORMAT,
                    INT_RECT_ARGS(pc.prerendered->area));
            pc.prerendered.clear();
        } else {
            drawArea.unite(pc.prerendered->area);
            SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height());
            nwayCanvas->translate(-drawArea.x(), -drawArea.y());
            nwayCanvas->addCanvas(canvas);
            nwayCanvas->addCanvas(prerender);
            SkSafeUnref(canvas);
            SkSafeUnref(prerender);
            canvas = nwayCanvas;
        }
    }
    WebCore::PlatformGraphicsContextSkia pgc(canvas);
    WebCore::GraphicsContext gc(&pgc);
    ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea));
    painter->paintContents(&gc, drawArea);
    SkSafeUnref(canvas);
    picture->endRecording();

    SkSafeUnref(pc.picture);
    pc.picture = picture;
    pc.dirty = false;
}
Esempio n. 5
0
void PicturePile::applyWebkitInvals()
{
    m_dirtyRegion.setEmpty();
    if (!m_webkitInvals.size())
        return;
    // Build the invals (TODO: Support multiple inval regions)
    IntRect inval = m_webkitInvals[0];
    m_dirtyRegion.setRect(toSkIRect(inval));
    for (size_t i = 1; i < m_webkitInvals.size(); i++) {
        inval.unite(m_webkitInvals[i]);
        m_dirtyRegion.op(toSkIRect(m_webkitInvals[i]), SkRegion::kUnion_Op);
    }
    m_webkitInvals.clear();
    ALOGV("Webkit inval: " INT_RECT_FORMAT, INT_RECT_ARGS(inval));
    if (inval.isEmpty())
        return;

    // Find the overlaps
    Vector<int> overlaps;
    for (size_t i = 0; i < m_pile.size(); i++) {
        PictureContainer& pc = m_pile[i];
        if (pc.area.contains(inval)) {
            if (pc.dirty) {
                ALOGV("Found already dirty intersection");
                return;
            }
            if (pc.area == inval) {
                appendToPile(inval);
                return;
            }
            // Don't count the base surface as an overlap
            if (pc.area.size() != m_size)
                overlaps.append(i);
        } else if (pc.area.intersects(inval))
            overlaps.append(i);
    }

    if (overlaps.size() >= MAX_OVERLAP_COUNT) {
        ALOGV("Exceeds overlap count");
        IntRect overlap = inval;
        for (int i = (int) overlaps.size() - 1; i >= 0; i--) {
            overlap.unite(m_pile[overlaps[i]].area);
            m_pile.remove(overlaps[i]);
        }
        float overlapArea = overlap.width() * overlap.height();
        float totalArea = m_size.width() * m_size.height();
        if (overlapArea / totalArea > MAX_OVERLAP_AREA)
            overlap = IntRect(0, 0, m_size.width(), m_size.height());
        appendToPile(overlap, inval);
        return;
    }

    // Append!
    appendToPile(inval);
}
Esempio n. 6
0
// Used by WebViewCore
void PicturePile::invalidate(const IntRect& dirtyRect)
{
    // This will typically happen if the document has been resized but we haven't
    // drawn yet. As the first draw after a size change will do a full inval anyway,
    // don't bother tracking individual rects
    // TODO: Instead of clipping here, we should take the invals as given
    // and when the size changes just inval the deltas. This prevents a full
    // redraw for a page that grows
    IntRect inval = dirtyRect;
    inval.intersect(IntRect(0, 0, m_size.width(), m_size.height()));
    if (inval.isEmpty()) {
        ALOGV("Rejecting inval " INT_RECT_FORMAT, INT_RECT_ARGS(dirtyRect));
        return;
    }
    // TODO: Support multiple non-intersecting webkit invals
    if (m_webkitInvals.size())
        m_webkitInvals[0].unite(inval);
    else
        m_webkitInvals.append(inval);
}
Esempio n. 7
0
bool Surface::blitFromContents(Tile* tile)
{
    if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content())
        return false;

    if (tile->frontTexture() != tile->lastDrawnTexture()) {
        // CAPPFIX_FLICKERING: fix flickering issue at floating browser mode
        return false;
        // CAPPFIX_FLICKERING_END

        // the below works around an issue where glTexSubImage2d can't update a
        // texture that hasn't drawn yet by drawing it off screen.
        // glFlush() and glFinish() work also, but are likely more wasteful.
        SkRect rect = SkRect::MakeXYWH(-100, -100, 0, 0);
        FloatRect fillPortion(0, 0, 0, 0);
        tile->frontTexture()->drawGL(false, rect, 1.0f, 0, false, true, fillPortion);
    }
    LayerContent* content = getFirstLayer()->content();
    // Extract the dirty rect from the region. Note that this is *NOT* constrained
    // to this tile
    IntRect dirtyRect = tile->dirtyArea().getBounds();
    IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(),
                               tile->y() * TilesManager::tileHeight(),
                               TilesManager::tileWidth(),
                               TilesManager::tileHeight());
    FloatRect tileRectInDoc = tileRect;
    tileRectInDoc.scale(1 / tile->scale());
    dirtyRect.intersect(enclosingIntRect(tileRectInDoc));
    PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect);
    if (!prerenderedInval || prerenderedInval->bitmap.isNull())
        return false;
    SkBitmap sourceBitmap = prerenderedInval->bitmap;
    // Calculate the screen rect that is dirty, then intersect it with the
    // tile's screen rect so that we end up with the pixels we need to blit
    FloatRect screenDirty = dirtyRect;
    screenDirty.scale(tile->scale());
    IntRect enclosingScreenDirty = enclosingIntRect(screenDirty);
    enclosingScreenDirty.intersect(tileRect);
    if (enclosingScreenDirty.isEmpty())
        return false;
    // Make sure the screen area we want to blit is contained by the
    // prerendered screen area
    if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) {
        ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain "
                "enclosingScreenDirty " INT_RECT_FORMAT,
                INT_RECT_ARGS(prerenderedInval->screenArea),
                INT_RECT_ARGS(enclosingScreenDirty));
        return false;
    }
    IntPoint origin = prerenderedInval->screenArea.location();
    SkBitmap subset;
    subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(),
            enclosingScreenDirty.height());
    subset.allocPixels();

    int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y();
    int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x();
    if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset))
        return false;
    // Now upload
    SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(),
                                             enclosingScreenDirty.y() - tileRect.y(),
                                             enclosingScreenDirty.width(),
                                             enclosingScreenDirty.height());
    GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId,
                                     subset, textureInval);
    tile->onBlitUpdate();
    return true;
}