static void paintWebView(WebKitWebView* webView, Frame* frame, const Region& dirtyRegion)
{
    if (!webView->priv->backingStore)
        return;

    Vector<IntRect> rects = dirtyRegion.rects();
    coalesceRectsIfPossible(dirtyRegion.bounds(), rects);

    RefPtr<cairo_t> backingStoreContext = adoptRef(cairo_create(webView->priv->backingStore->cairoSurface()));
    GraphicsContext gc(backingStoreContext.get());
    gc.applyDeviceScaleFactor(frame->page()->deviceScaleFactor());
    for (size_t i = 0; i < rects.size(); i++) {
        const IntRect& rect = rects[i];

        gc.save();
        gc.clip(rect);
        if (webView->priv->transparent)
            gc.clearRect(rect);
        frame->view()->paint(&gc, rect);
        gc.restore();
    }

    gc.save();
    gc.clip(dirtyRegion.bounds());
    frame->page()->inspectorController()->drawHighlight(gc);
    gc.restore();
}
Esempio n. 2
0
void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOptions& options)
{
    Region overlapRegion;
    Region nonOverlapRegion;
    computeOverlapRegions(overlapRegion, nonOverlapRegion, ResolveSelfOverlapAlways);
    if (overlapRegion.isEmpty()) {
        paintSelfAndChildrenWithReplica(options);
        return;
    }

    // Having both overlap and non-overlap regions carries some overhead. Avoid it if the overlap area
    // is big anyway.
    if (overlapRegion.bounds().size().area() > nonOverlapRegion.bounds().size().area()) {
        overlapRegion.unite(nonOverlapRegion);
        nonOverlapRegion = Region();
    }

    nonOverlapRegion.translate(options.offset);
    Vector<IntRect> rects = nonOverlapRegion.rects();

    for (size_t i = 0; i < rects.size(); ++i) {
        IntRect rect = rects[i];
        if (!rect.intersects(options.textureMapper->clipBounds()))
            continue;

        options.textureMapper->beginClip(TransformationMatrix(), rects[i]);
        paintSelfAndChildrenWithReplica(options);
        options.textureMapper->endClip();
    }

    rects = overlapRegion.rects();
    static const size_t OverlapRegionConsolidationThreshold = 4;
    if (nonOverlapRegion.isEmpty() && rects.size() > OverlapRegionConsolidationThreshold) {
        rects.clear();
        rects.append(overlapRegion.bounds());
    }

    IntSize maxTextureSize = options.textureMapper->maxTextureSize();
    IntRect adjustedClipBounds(options.textureMapper->clipBounds());
    adjustedClipBounds.move(-options.offset);
    for (size_t i = 0; i < rects.size(); ++i) {
        IntRect rect = rects[i];
        for (int x = rect.x(); x < rect.maxX(); x += maxTextureSize.width()) {
            for (int y = rect.y(); y < rect.maxY(); y += maxTextureSize.height()) {
                IntRect tileRect(IntPoint(x, y), maxTextureSize);
                tileRect.intersect(rect);
                if (!tileRect.intersects(adjustedClipBounds))
                    continue;

                paintWithIntermediateSurface(options, tileRect);
            }
        }
    }
}
Esempio n. 3
0
void TextureMapperLayer::computeOverlapRegions(Region& overlapRegion, Region& nonOverlapRegion, ResolveSelfOverlapMode mode)
{
    if (!m_state.visible || !m_state.contentsVisible)
        return;

    FloatRect boundingRect;
    if (m_backingStore || m_state.masksToBounds || m_state.maskLayer || hasFilters())
        boundingRect = layerRect();
    else if (m_contentsLayer || m_state.solidColor.alpha())
        boundingRect = m_state.contentsRect;

    if (m_currentFilters.hasOutsets()) {
        FilterOutsets outsets = m_currentFilters.outsets();
        IntRect unfilteredTargetRect(boundingRect);
        boundingRect.move(std::max(0, -outsets.left()), std::max(0, -outsets.top()));
        boundingRect.expand(outsets.left() + outsets.right(), outsets.top() + outsets.bottom());
        boundingRect.unite(unfilteredTargetRect);
    }

    TransformationMatrix replicaMatrix;
    if (m_state.replicaLayer) {
        replicaMatrix = replicaTransform();
        boundingRect.unite(replicaMatrix.mapRect(boundingRect));
    }

    boundingRect = m_currentTransform.combined().mapRect(boundingRect);

    // Count all masks and filters as overlap layers.
    if (hasFilters() || m_state.maskLayer || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)) {
        Region newOverlapRegion(enclosingIntRect(boundingRect));
        nonOverlapRegion.subtract(newOverlapRegion);
        overlapRegion.unite(newOverlapRegion);
        return;
    }

    Region newOverlapRegion;
    Region newNonOverlapRegion(enclosingIntRect(boundingRect));

    if (!m_state.masksToBounds) {
        for (auto* child : m_children)
            child->computeOverlapRegions(newOverlapRegion, newNonOverlapRegion, ResolveSelfOverlapIfNeeded);
    }

    if (m_state.replicaLayer) {
        newOverlapRegion.unite(replicaMatrix.mapRect(newOverlapRegion.bounds()));
        Region replicaRegion(replicaMatrix.mapRect(newNonOverlapRegion.bounds()));
        resolveOverlaps(replicaRegion, newOverlapRegion, newNonOverlapRegion);
    }

    if ((mode != ResolveSelfOverlapAlways) && shouldBlend()) {
        newNonOverlapRegion.unite(newOverlapRegion);
        newOverlapRegion = Region();
    }

    overlapRegion.unite(newOverlapRegion);
    resolveOverlaps(newNonOverlapRegion, overlapRegion, nonOverlapRegion);
}
Esempio n. 4
0
TEST(Region, Equal)
{
  Region a;
  a = Rect(2, 3, 4, 5);
  EXPECT_EQ(Rect(2, 3, 4, 5), a.bounds());
  EXPECT_EQ(Rect(2, 3, 4, 5), a[0]);
  EXPECT_FALSE(a.isEmpty());

  a = Rect(6, 7, 8, 9);
  EXPECT_EQ(Rect(6, 7, 8, 9), a.bounds());
  EXPECT_EQ(Rect(6, 7, 8, 9), a[0]);

  Region b;
  b = a;
  EXPECT_EQ(Rect(6, 7, 8, 9), b[0]);

  b = Rect(0, 0, 0, 0);
  EXPECT_TRUE(b.isEmpty());
}
Esempio n. 5
0
	void ChromeClientJS::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect)
	{
		webkitTrace();

		if (m_view->m_private->acceleratedContext && m_view->m_private->acceleratedContext->enabled()) {
			ASSERT(!rectToScroll.isEmpty());
			ASSERT(delta.width() || delta.height());
			m_view->m_private->acceleratedContext->scrollNonCompositedContents(rectToScroll, delta);
			return;
		}

		m_rectsToScroll.append(rectToScroll);
		m_scrollOffsets.append(delta);

		// The code to calculate the scroll repaint region is originally from WebKit2.
		// Get the part of the dirty region that is in the scroll rect.
		Region dirtyRegionInScrollRect = intersect(rectToScroll, m_dirtyRegion);
		if (!dirtyRegionInScrollRect.isEmpty()) {
			// There are parts of the dirty region that are inside the scroll rect.
			// We need to subtract them from the region, move them and re-add them.
			Region dirtyRegion = Region(m_dirtyRegion);
			dirtyRegion.subtract(rectToScroll);
			m_dirtyRegion = dirtyRegion.bounds();

			// Move the dirty parts.
			Region movedDirtyRegionInScrollRect = intersect(translate(dirtyRegionInScrollRect, delta), rectToScroll);

			// And add them back.
			m_dirtyRegion.unite(movedDirtyRegionInScrollRect.bounds());
		}

		// Compute the scroll repaint region. We ensure that we are not subtracting areas
		// that we've scrolled from outside the viewport from the repaint region.
		IntRect onScreenScrollRect = rectToScroll;
		onScreenScrollRect.intersect(IntRect(IntPoint(), enclosingIntRect(pageRect()).size()));
		Region scrollRepaintRegion = subtract(rectToScroll, translate(onScreenScrollRect, delta));

		m_dirtyRegion.unite(scrollRepaintRegion.bounds());
		m_displayTimer.startOneShot(0);
	}
Esempio n. 6
0
Region Transform::transform(const Region& reg) const
{
    Region out;
    if (UNLIKELY(transformed())) {
        if (LIKELY(preserveRects())) {
            Rect r;
            Region::iterator iterator(reg);
            while (iterator.iterate(&r)) {
                out.orSelf(transform(r));
            }
        } else {
            out.set(transform(reg.bounds()));
        }
    } else {
        out = reg.translate(tx(), ty());
    }
    return out;
}
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;
}
Region Transform::transform(const Region& reg) const
{
    Region out;
    if (CC_UNLIKELY(type() > TRANSLATE)) {
        if (CC_LIKELY(preserveRects())) {
            Region::const_iterator it = reg.begin();
            Region::const_iterator const end = reg.end();
            while (it != end) {
                out.orSelf(transform(*it++));
            }
        } else {
            out.set(transform(reg.bounds()));
        }
    } else {
        int xpos = floorf(tx() + 0.5f);
        int ypos = floorf(ty() + 0.5f);
        out = reg.translate(xpos, ypos);
    }
    return out;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
void ToolLoopManager::calculateDirtyArea(const Points& points)
{
  // Save the current dirty area if it's needed
  Region prevDirtyArea;
  if (m_toolLoop->getTracePolicy() == TracePolicy::Last)
    prevDirtyArea = m_dirtyArea;

  // Start with a fresh dirty area
  m_dirtyArea.clear();

  if (points.size() > 0) {
    Point minpt, maxpt;
    calculateMinMax(points, minpt, maxpt);

    // Expand the dirty-area with the pen width
    Rect r1, r2;
    m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, minpt.x, minpt.y, r1);
    m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, maxpt.x, maxpt.y, r2);

    m_dirtyArea.createUnion(m_dirtyArea, Region(r1.createUnion(r2)));
  }

  // Apply offset mode
  Point offset(m_toolLoop->getOffset());
  m_dirtyArea.offset(-offset);

  // Merge new dirty area with the previous one (for tools like line
  // or rectangle it's needed to redraw the previous position and
  // the new one)
  if (m_toolLoop->getTracePolicy() == TracePolicy::Last)
    m_dirtyArea.createUnion(m_dirtyArea, prevDirtyArea);

  // Apply tiled mode
  TiledMode tiledMode = m_toolLoop->getTiledMode();
  if (tiledMode != TiledMode::NONE) {
    int w = m_toolLoop->sprite()->width();
    int h = m_toolLoop->sprite()->height();
    Region sprite_area(Rect(0, 0, w, h));
    Region outside;
    outside.createSubtraction(m_dirtyArea, sprite_area);

    switch (tiledMode) {
      case TiledMode::X_AXIS:
        outside.createIntersection(outside, Region(Rect(-w*10000, 0, w*20000, h)));
        break;
      case TiledMode::Y_AXIS:
        outside.createIntersection(outside, Region(Rect(0, -h*10000, w, h*20000)));
        break;
    }

    Rect outsideBounds = outside.bounds();
    if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0);
    if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h)));
    int x1 = outside.bounds().x;

    while (true) {
      Region in_sprite;
      in_sprite.createIntersection(outside, sprite_area);
      outside.createSubtraction(outside, in_sprite);
      m_dirtyArea.createUnion(m_dirtyArea, in_sprite);

      outsideBounds = outside.bounds();
      if (outsideBounds.isEmpty())
        break;
      else if (outsideBounds.x+outsideBounds.w > w)
        outside.offset(-w, 0);
      else if (outsideBounds.y+outsideBounds.h > h)
        outside.offset(x1-outsideBounds.x, -h);
      else
        break;
    }
  }
}
Esempio n. 11
0
status_t TextureManager::loadTexture(Texture* texture,
        const Region& dirty, const GGLSurface& t)
{
    if (texture->name == -1UL) {
        status_t err = initTexture(texture);
        LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err));
        return err;
    }

    if (texture->target != Texture::TEXTURE_2D)
        return INVALID_OPERATION;

    glBindTexture(GL_TEXTURE_2D, texture->name);

    /*
     * In OpenGL ES we can't specify a stride with glTexImage2D (however,
     * GL_UNPACK_ALIGNMENT is a limited form of stride).
     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
     * need to do something reasonable (here creating a bigger texture).
     *
     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
     *
     * This situation doesn't happen often, but some h/w have a limitation
     * for their framebuffer (eg: must be multiple of 8 pixels), and
     * we need to take that into account when using these buffers as
     * textures.
     *
     * This should never be a problem with POT textures
     */

    int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
    unpack = 1 << ((unpack > 3) ? 3 : unpack);
    glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);

    /*
     * round to POT if needed
     */
    if (!mGLExtensions.haveNpot()) {
        texture->NPOTAdjust = true;
    }

    if (texture->NPOTAdjust) {
        // find the smallest power-of-two that will accommodate our surface
        texture->potWidth  = 1 << (31 - clz(t.width));
        texture->potHeight = 1 << (31 - clz(t.height));
        if (texture->potWidth  < t.width)  texture->potWidth  <<= 1;
        if (texture->potHeight < t.height) texture->potHeight <<= 1;
        texture->wScale = float(t.width)  / texture->potWidth;
        texture->hScale = float(t.height) / texture->potHeight;
    } else {
        texture->potWidth  = t.width;
        texture->potHeight = t.height;
    }

    Rect bounds(dirty.bounds());
    GLvoid* data = 0;
    if (texture->width != t.width || texture->height != t.height) {
        texture->width  = t.width;
        texture->height = t.height;

        // texture size changed, we need to create a new one
        bounds.set(Rect(t.width, t.height));
        if (t.width  == texture->potWidth &&
            t.height == texture->potHeight) {
            // we can do it one pass
            data = t.data;
        }

        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
            glTexImage2D(GL_TEXTURE_2D, 0,
                    GL_RGB, texture->potWidth, texture->potHeight, 0,
                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
            glTexImage2D(GL_TEXTURE_2D, 0,
                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
            glTexImage2D(GL_TEXTURE_2D, 0,
                    GL_RGBA, texture->potWidth, texture->potHeight, 0,
                    GL_RGBA, GL_UNSIGNED_BYTE, data);
        } else if (isSupportedYuvFormat(t.format)) {
            // just show the Y plane of YUV buffers
            glTexImage2D(GL_TEXTURE_2D, 0,
                    GL_LUMINANCE, texture->potWidth, texture->potHeight, 0,
                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
        } else {
            // oops, we don't handle this format!
            LOGE("texture=%d, using format %d, which is not "
                 "supported by the GL", texture->name, t.format);
        }
    }
    if (!data) {
        if (t.format == HAL_PIXEL_FORMAT_RGB_565) {
            glTexSubImage2D(GL_TEXTURE_2D, 0,
                    0, bounds.top, t.width, bounds.height(),
                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
                    t.data + bounds.top*t.stride*2);
        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) {
            glTexSubImage2D(GL_TEXTURE_2D, 0,
                    0, bounds.top, t.width, bounds.height(),
                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
                    t.data + bounds.top*t.stride*2);
        } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 ||
                   t.format == HAL_PIXEL_FORMAT_RGBX_8888) {
            glTexSubImage2D(GL_TEXTURE_2D, 0,
                    0, bounds.top, t.width, bounds.height(),
                    GL_RGBA, GL_UNSIGNED_BYTE,
                    t.data + bounds.top*t.stride*4);
        } else if (isSupportedYuvFormat(t.format)) {
            // just show the Y plane of YUV buffers
            glTexSubImage2D(GL_TEXTURE_2D, 0,
                    0, bounds.top, t.width, bounds.height(),
                    GL_LUMINANCE, GL_UNSIGNED_BYTE,
                    t.data + bounds.top*t.stride);
        }
    }
    return NO_ERROR;
}
Esempio n. 12
0
void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, Region& dirty_area)
{
  dirty_area.clear();

  if (points.size() > 0) {
    Point minpt, maxpt;
    calculateMinMax(points, minpt, maxpt);

    // Expand the dirty-area with the pen width
    Rect r1, r2;
    loop->getPointShape()->getModifiedArea(loop, minpt.x, minpt.y, r1);
    loop->getPointShape()->getModifiedArea(loop, maxpt.x, maxpt.y, r2);

    dirty_area.createUnion(dirty_area, Region(r1.createUnion(r2)));
  }

  // Apply offset mode
  Point offset(loop->getOffset());
  dirty_area.offset(-offset);

  // Apply tiled mode
  TiledMode tiledMode = loop->getDocumentSettings()->getTiledMode();
  if (tiledMode != TILED_NONE) {
    int w = loop->sprite()->width();
    int h = loop->sprite()->height();
    Region sprite_area(Rect(0, 0, w, h));
    Region outside;
    outside.createSubtraction(dirty_area, sprite_area);

    switch (tiledMode) {
      case TILED_X_AXIS:
        outside.createIntersection(outside, Region(Rect(-w*10000, 0, w*20000, h)));
        break;
      case TILED_Y_AXIS:
        outside.createIntersection(outside, Region(Rect(0, -h*10000, w, h*20000)));
        break;
    }

    Rect outsideBounds = outside.bounds();
    if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0);
    if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h)));
    int x1 = outside.bounds().x;

    while (true) {
      Region in_sprite;
      in_sprite.createIntersection(outside, sprite_area);
      outside.createSubtraction(outside, in_sprite);
      dirty_area.createUnion(dirty_area, in_sprite);

      outsideBounds = outside.bounds();
      if (outsideBounds.isEmpty())
        break;
      else if (outsideBounds.x+outsideBounds.w > w)
        outside.offset(-w, 0);
      else if (outsideBounds.y+outsideBounds.h > h)
        outside.offset(x1-outsideBounds.x, -h);
      else
        break;
    }
  }
}
Esempio n. 13
0
// Strokes are relative to sprite origin.
void ToolLoopManager::calculateDirtyArea(const Strokes& strokes)
{
  // Save the current dirty area if it's needed
  Region prevDirtyArea;
  if (m_toolLoop->getTracePolicy() == TracePolicy::Last)
    prevDirtyArea = m_dirtyArea;

  // Start with a fresh dirty area
  m_dirtyArea.clear();

  const Point celOrigin = m_toolLoop->getCelOrigin();

  for (auto& stroke : strokes) {
    gfx::Rect strokeBounds = stroke.bounds();
    if (strokeBounds.isEmpty())
      continue;

    // Expand the dirty-area with the pen width
    Rect r1, r2;

    m_toolLoop->getPointShape()->getModifiedArea(
      m_toolLoop,
      strokeBounds.x - celOrigin.x,
      strokeBounds.y - celOrigin.y, r1);

    m_toolLoop->getPointShape()->getModifiedArea(
      m_toolLoop,
      strokeBounds.x+strokeBounds.w-1 - celOrigin.x,
      strokeBounds.y+strokeBounds.h-1 - celOrigin.y, r2);

    m_dirtyArea.createUnion(m_dirtyArea, Region(r1.createUnion(r2)));
  }

  // Make the dirty area relative to the sprite.
  m_dirtyArea.offset(celOrigin);

  // Merge new dirty area with the previous one (for tools like line
  // or rectangle it's needed to redraw the previous position and
  // the new one)
  if (m_toolLoop->getTracePolicy() == TracePolicy::Last)
    m_dirtyArea.createUnion(m_dirtyArea, prevDirtyArea);

  // Apply tiled mode
  TiledMode tiledMode = m_toolLoop->getTiledMode();
  if (tiledMode != TiledMode::NONE) {
    int w = m_toolLoop->sprite()->width();
    int h = m_toolLoop->sprite()->height();
    Region sprite_area(Rect(0, 0, w, h));
    Region outside;
    outside.createSubtraction(m_dirtyArea, sprite_area);

    switch (tiledMode) {
      case TiledMode::X_AXIS:
        outside.createIntersection(outside, Region(Rect(-w*10000, 0, w*20000, h)));
        break;
      case TiledMode::Y_AXIS:
        outside.createIntersection(outside, Region(Rect(0, -h*10000, w, h*20000)));
        break;
    }

    Rect outsideBounds = outside.bounds();
    if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0);
    if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h)));
    int x1 = outside.bounds().x;

    while (true) {
      Region in_sprite;
      in_sprite.createIntersection(outside, sprite_area);
      outside.createSubtraction(outside, in_sprite);
      m_dirtyArea.createUnion(m_dirtyArea, in_sprite);

      outsideBounds = outside.bounds();
      if (outsideBounds.isEmpty())
        break;
      else if (outsideBounds.x+outsideBounds.w > w)
        outside.offset(-w, 0);
      else if (outsideBounds.y+outsideBounds.h > h)
        outside.offset(x1-outsideBounds.x, -h);
      else
        break;
    }
  }
}
Esempio n. 14
0
void LayerBase::loadTexture(const Region& dirty,
        GLint textureName, const GGLSurface& t,
        GLuint& textureWidth, GLuint& textureHeight) const
{
    // TODO: defer the actual texture reload until LayerBase::validateTexture
    // is called.

    uint32_t flags = mFlags;
    glBindTexture(GL_TEXTURE_2D, textureName);

    GLuint tw = t.width;
    GLuint th = t.height;

    /*
     * In OpenGL ES we can't specify a stride with glTexImage2D (however,
     * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of
     * stride).
     * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
     * need to do something reasonable (here creating a bigger texture).
     * 
     * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT);
     * 
     * This situation doesn't happen often, but some h/w have a limitation
     * for their framebuffer (eg: must be multiple of 8 pixels), and
     * we need to take that into account when using these buffers as
     * textures.
     *
     * This should never be a problem with POT textures
     */

    tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);

    /*
     * round to POT if needed 
     */
    
    GLuint texture_w = tw;
    GLuint texture_h = th;
    if (!(flags & DisplayHardware::NPOT_EXTENSION)) {
        // find the smallest power-of-two that will accommodate our surface
        texture_w = 1 << (31 - clz(t.width));
        texture_h = 1 << (31 - clz(t.height));
        if (texture_w < t.width)  texture_w <<= 1;
        if (texture_h < t.height) texture_h <<= 1;
        if (texture_w != tw || texture_h != th) {
            // we can't use DIRECT_TEXTURE since we changed the size
            // of the texture
            flags &= ~DisplayHardware::DIRECT_TEXTURE;
        }
    }

    if (flags & DisplayHardware::DIRECT_TEXTURE) {
        // here we're guaranteed that texture_{w|h} == t{w|h}
        if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
            glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
                    GL_RGB, tw, th, 0,
                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
            glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
                    GL_RGBA, tw, th, 0,
                    GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
        } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
            glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
                    GL_RGBA, tw, th, 0,
                    GL_RGBA, GL_UNSIGNED_BYTE, t.data);
        } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
            // TODO: add GL_BGRA extension
        } else {
            // oops, we don't handle this format, try the regular path
            goto regular;
        }
        textureWidth = tw;
        textureHeight = th;
    } else {
regular:
        Rect bounds(dirty.bounds());
        GLvoid* data = 0;
        if (texture_w!=textureWidth || texture_h!=textureHeight) {
            // texture size changed, we need to create a new one

            if (!textureWidth || !textureHeight) {
                // this is the first time, load the whole texture
                if (texture_w==tw && texture_h==th) {
                    // we can do it one pass
                    data = t.data;
                } else {
                    // we have to create the texture first because it
                    // doesn't match the size of the buffer
                    bounds.set(Rect(tw, th));
                }
            }
            
            if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
                glTexImage2D(GL_TEXTURE_2D, 0,
                        GL_RGB, texture_w, texture_h, 0,
                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
                glTexImage2D(GL_TEXTURE_2D, 0,
                        GL_RGBA, texture_w, texture_h, 0,
                        GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
                glTexImage2D(GL_TEXTURE_2D, 0,
                        GL_RGBA, texture_w, texture_h, 0,
                        GL_RGBA, GL_UNSIGNED_BYTE, data);
            } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
                        t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
                // just show the Y plane of YUV buffers
                data = t.data;
                glTexImage2D(GL_TEXTURE_2D, 0,
                        GL_LUMINANCE, texture_w, texture_h, 0,
                        GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
            } else {
                // oops, we don't handle this format!
                LOGE("layer %p, texture=%d, using format %d, which is not "
                     "supported by the GL", this, textureName, t.format);
                textureName = -1;
            }
            textureWidth = texture_w;
            textureHeight = texture_h;
        }
        if (!data && textureName>=0) {
            if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
                glTexSubImage2D(GL_TEXTURE_2D, 0,
                        0, bounds.top, t.width, bounds.height(),
                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
                        t.data + bounds.top*t.width*2);
            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
                glTexSubImage2D(GL_TEXTURE_2D, 0,
                        0, bounds.top, t.width, bounds.height(),
                        GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
                        t.data + bounds.top*t.width*2);
            } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
                glTexSubImage2D(GL_TEXTURE_2D, 0,
                        0, bounds.top, t.width, bounds.height(),
                        GL_RGBA, GL_UNSIGNED_BYTE,
                        t.data + bounds.top*t.width*4);
            }
        }
    }
}