void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* targetSurface)
{
    if (layer->renderSurface() && layer->renderSurface() != targetSurface) {
        layer->renderSurface()->draw(layer->getDrawRect());
        return;
    }

    if (!layer->drawsContent())
        return;

    if (layer->bounds().isEmpty()) {
        layer->unreserveContentsTexture();
        return;
    }

    setScissorToRect(layer->scissorRect());

    IntRect targetSurfaceRect = m_currentRenderSurface ? m_currentRenderSurface->contentRect() : m_defaultRenderSurface->contentRect();
    IntRect scissorRect = layer->scissorRect();
    if (!scissorRect.isEmpty())
        targetSurfaceRect.intersect(scissorRect);

    // Check if the layer falls within the visible bounds of the page.
    IntRect layerRect = layer->getDrawRect();
    bool isLayerVisible = targetSurfaceRect.intersects(layerRect);
    if (!isLayerVisible) {
        layer->unreserveContentsTexture();
        return;
    }

    // FIXME: Need to take into account the commulative render surface transforms all the way from
    //        the default render surface in order to determine visibility.
    TransformationMatrix combinedDrawMatrix = (layer->targetRenderSurface() ? layer->targetRenderSurface()->drawTransform().multiply(layer->drawTransform()) : layer->drawTransform());
    
    if (!layer->doubleSided()) {
        FloatRect layerRect(FloatPoint(0, 0), FloatSize(layer->bounds()));
        FloatQuad mappedLayer = combinedDrawMatrix.mapQuad(FloatQuad(layerRect));
        FloatSize horizontalDir = mappedLayer.p2() - mappedLayer.p1();
        FloatSize verticalDir = mappedLayer.p4() - mappedLayer.p1();
        FloatPoint3D xAxis(horizontalDir.width(), horizontalDir.height(), 0);
        FloatPoint3D yAxis(verticalDir.width(), verticalDir.height(), 0);
        FloatPoint3D zAxis = xAxis.cross(yAxis);
        if (zAxis.z() < 0) {
            layer->unreserveContentsTexture();
            return;
        }
    }

    layer->draw(targetSurfaceRect);

    // Draw the debug border if there is one.
    layer->drawDebugBorder();
}
示例#2
0
LayoutRect RenderLayerClipper::childrenClipRect() const
{
    // FIXME: border-radius not accounted for.
    // FIXME: Regions not accounted for.
    RenderLayer* clippingRootLayer = clippingRootForPainting();
    LayoutRect layerBounds;
    ClipRect backgroundRect, foregroundRect, outlineRect;
    // Need to use uncached clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>).
    ClipRectsContext context(clippingRootLayer, UncachedClipRects);
    calculateRects(context, m_renderer.view()->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
    return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox();
}
示例#3
0
bool RenderWidget::updateWidgetGeometry()
{
    Widget* widget = this->widget();
    ASSERT(widget);

    LayoutRect contentBox = contentBoxRect();
    LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
    if (widget->isFrameView()) {
        contentBox.setLocation(absoluteContentBox.location());
        return setWidgetGeometry(contentBox);
    }

    return setWidgetGeometry(absoluteContentBox);
}
IntRect CoordinatedGraphicsLayer::tiledBackingStoreVisibleRect()
{
    // Non-invertible layers are not visible.
    if (!m_layerTransform.combined().isInvertible())
        return IntRect();

    // Return a projection of the visible rect (surface coordinates) onto the layer's plane (layer coordinates).
    // The resulting quad might be squewed and the visible rect is the bounding box of this quad,
    // so it might spread further than the real visible area (and then even more amplified by the cover rect multiplier).
    ASSERT(m_cachedInverseTransform == m_layerTransform.combined().inverse());
    FloatRect rect = m_cachedInverseTransform.clampedBoundsOfProjectedQuad(FloatQuad(m_coordinator->visibleContentsRect()));
    clampToContentsRectIfRectIsInfinite(rect, tiledBackingStoreContentsRect());
    return enclosingIntRect(rect);
}
示例#5
0
void LayerRendererChromium::drawLayer(CCLayerImpl* layer, CCRenderSurface* targetSurface)
{
    if (layer->renderSurface() && layer->renderSurface() != targetSurface) {
        layer->renderSurface()->draw(this, layer->getDrawRect());
        layer->renderSurface()->releaseContentsTexture();
        return;
    }

    if (!layer->drawsContent())
        return;

    if (!layer->opacity())
        return;

    if (layer->bounds().isEmpty())
        return;

    IntRect targetSurfaceRect = layer->targetRenderSurface() ? layer->targetRenderSurface()->contentRect() : m_defaultRenderSurface->contentRect();
    if (layer->usesLayerScissor()) {
        IntRect scissorRect = layer->scissorRect();
        targetSurfaceRect.intersect(scissorRect);
        if (targetSurfaceRect.isEmpty())
            return;
        setScissorToRect(scissorRect);
    } else
        GLC(m_context.get(), m_context->disable(GraphicsContext3D::SCISSOR_TEST));

    IntRect visibleLayerRect = CCLayerTreeHostCommon::calculateVisibleLayerRect(targetSurfaceRect, layer->bounds(), layer->contentBounds(), layer->drawTransform());
    visibleLayerRect.move(toSize(layer->scrollPosition()));
    layer->setVisibleLayerRect(visibleLayerRect);

    // The layer should not be drawn if (1) it is not double-sided and (2) the back of the layer is facing the screen.
    // This second condition is checked by computing the transformed normal of the layer.
    if (!layer->doubleSided()) {
        FloatRect layerRect(FloatPoint(0, 0), FloatSize(layer->bounds()));
        FloatQuad mappedLayer = layer->screenSpaceTransform().mapQuad(FloatQuad(layerRect));
        FloatSize horizontalDir = mappedLayer.p2() - mappedLayer.p1();
        FloatSize verticalDir = mappedLayer.p4() - mappedLayer.p1();
        FloatPoint3D xAxis(horizontalDir.width(), horizontalDir.height(), 0);
        FloatPoint3D yAxis(verticalDir.width(), verticalDir.height(), 0);
        FloatPoint3D zAxis = xAxis.cross(yAxis);
        if (zAxis.z() < 0)
            return;
    }

    layer->draw(this);

    // Draw the debug border if there is one.
    layer->drawDebugBorder(this);
}
示例#6
0
bool RenderWidget::updateWidgetGeometry()
{
    if (!m_widget->transformsAffectFrameRect())
        return setWidgetGeometry(absoluteContentBox());

    LayoutRect contentBox = contentBoxRect();
    LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
    if (m_widget->isFrameView()) {
        contentBox.setLocation(absoluteContentBox.location());
        return setWidgetGeometry(contentBox);
    }

    return setWidgetGeometry(absoluteContentBox);
}
示例#7
0
IntRect WebGraphicsLayer::tiledBackingStoreVisibleRect()
{
    if (!shouldUseTiledBackingStore())
        return tiledBackingStoreContentsRect();

    // Non-invertible layers are not visible.
    if (!m_layerTransform.combined().isInvertible())
        return IntRect();

    // Return a projection of the visible rect (surface coordinates) onto the layer's plane (layer coordinates).
    // The resulting quad might be squewed and the visible rect is the bounding box of this quad,
    // so it might spread further than the real visible area (and then even more amplified by the cover rect multiplier).
    return m_layerTransform.combined().inverse().clampedBoundsOfProjectedQuad(FloatQuad(FloatRect(m_webGraphicsLayerClient->visibleContentsRect())));
}
void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset)
{
    // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks).
    if (m_scrollDimensionsDirty)
        computeScrollDimensions();

    if (scrollOffset() == toIntSize(newScrollOffset))
        return;

    setScrollOffset(toIntSize(newScrollOffset));

    LocalFrame* frame = box().frame();
    ASSERT(frame);

    RefPtr<FrameView> frameView = box().frameView();

    TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ScrollLayer", "data", InspectorScrollLayerEvent::data(&box()));

    const RenderLayerModelObject* paintInvalidationContainer = box().containerForPaintInvalidation();

    // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
    // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
    if (!frameView->isInPerformLayout()) {
        // If we're in the middle of layout, we'll just update layers once layout has finished.
        layer()->clipper().clearClipRectsIncludingDescendants();
        box().setPreviousPaintInvalidationRect(box().boundsRectForPaintInvalidation(paintInvalidationContainer));
        updateCompositingLayersAfterScroll();
    }

    // The caret rect needs to be invalidated after scrolling
    frame->selection().setCaretRectNeedsUpdate();

    FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect());

    quadForFakeMouseMoveEvent = paintInvalidationContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
    frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);

    // For querying RenderLayer::compositingState()
    // This code appears correct, since scrolling outside of layout happens during activities that do not dirty compositing state.
    DisableCompositingQueryAsserts disabler;
    if (box().frameView()->isInPerformLayout())
        box().setShouldDoFullPaintInvalidation(true);
    else
        box().invalidatePaintUsingContainer(paintInvalidationContainer, layer()->renderer()->previousPaintInvalidationRect(), InvalidationScroll);

    // Schedule the scroll DOM event.
    if (box().node())
        box().node()->document().enqueueScrollEventForNode(box().node());
}
示例#9
0
void CCRenderSurface::drawLayer(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform, int contentsTextureId)
{
    TransformationMatrix deviceMatrix = computeDeviceTransform(layerRenderer, drawTransform);

    // Can only draw surface if device matrix is invertible.
    if (!deviceMatrix.isInvertible())
        return;

    // Draw the background texture if there is one.
    if (m_backgroundTexture && m_backgroundTexture->isReserved())
        copyTextureToFramebuffer(layerRenderer, m_backgroundTexture->textureId(), m_contentRect.size(), drawTransform);

    FloatQuad quad = deviceMatrix.mapQuad(layerRenderer->sharedGeometryQuad());
    CCLayerQuad deviceRect = CCLayerQuad(FloatQuad(quad.boundingBox()));
    CCLayerQuad layerQuad = CCLayerQuad(quad);

    // Use anti-aliasing programs only when necessary.
    bool useAA = (!quad.isRectilinear() || !quad.boundingBox().isExpressibleAsIntRect());

    if (useAA) {
        deviceRect.inflateAntiAliasingDistance();
        layerQuad.inflateAntiAliasingDistance();
    }

    bool useMask = false;
    if (maskLayer && maskLayer->drawsContent())
        if (!maskLayer->bounds().isEmpty())
            useMask = true;

    // FIXME: pass in backgroundTextureId and blend the background in with this draw instead of having a separate drawBackground() pass.

    if (useMask) {
        if (useAA) {
            const LayerRendererChromium::RenderSurfaceMaskProgramAA* program = layerRenderer->renderSurfaceMaskProgramAA();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, program->fragmentShader().maskSamplerLocation(), program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation());
        } else {
            const LayerRendererChromium::RenderSurfaceMaskProgram* program = layerRenderer->renderSurfaceMaskProgram();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, program->fragmentShader().maskSamplerLocation(), -1, -1);
        }
    } else {
        if (useAA) {
            const LayerRendererChromium::RenderSurfaceProgramAA* program = layerRenderer->renderSurfaceProgramAA();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, -1, program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation());
        } else {
            const LayerRendererChromium::RenderSurfaceProgram* program = layerRenderer->renderSurfaceProgram();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, -1, -1, -1);
        }
    }
}
bool LayoutPart::updateWidgetGeometryInternal()
{
    Widget* widget = this->widget();
    ASSERT(widget);

    LayoutRect contentBox = contentBoxRect();
    LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(FloatRect(contentBox))).boundingBox());
    if (widget->isFrameView()) {
        if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled())
            contentBox.setLocation(absoluteContentBox.location());
        return setWidgetGeometry(contentBox);
    }
    // TODO(chrishtr): why are these widgets using an absolute rect for their frameRect?
    return setWidgetGeometry(absoluteContentBox);
}
示例#11
0
void CCRenderSurface::drawLayer(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform)
{
    TransformationMatrix renderMatrix = drawTransform;
    // Apply a scaling factor to size the quad from 1x1 to its intended size.
    renderMatrix.scale3d(m_contentRect.width(), m_contentRect.height(), 1);

    TransformationMatrix deviceMatrix = TransformationMatrix(layerRenderer->windowMatrix() * layerRenderer->projectionMatrix() * renderMatrix).to2dTransform();

    // Can only draw surface if device matrix is invertible.
    if (!deviceMatrix.isInvertible())
        return;

    FloatQuad quad = deviceMatrix.mapQuad(layerRenderer->sharedGeometryQuad());
    CCLayerQuad deviceRect = CCLayerQuad(FloatQuad(quad.boundingBox()));
    CCLayerQuad layerQuad = CCLayerQuad(quad);

    // Use anti-aliasing programs only when necessary.
    bool useAA = (!quad.isRectilinear() || !quad.boundingBox().isExpressibleAsIntRect());

    if (useAA) {
        deviceRect.inflateAntiAliasingDistance();
        layerQuad.inflateAntiAliasingDistance();
    }

    bool useMask = false;
    if (maskLayer && maskLayer->drawsContent())
        if (!maskLayer->bounds().isEmpty())
            useMask = true;

    if (useMask) {
        if (useAA) {
            const MaskProgramAA* program = layerRenderer->renderSurfaceMaskProgramAA();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, program->fragmentShader().maskSamplerLocation(), program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation());
        } else {
            const MaskProgram* program = layerRenderer->renderSurfaceMaskProgram();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, program->fragmentShader().maskSamplerLocation(), -1, -1);
        }
    } else {
        if (useAA) {
            const ProgramAA* program = layerRenderer->renderSurfaceProgramAA();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, -1, program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation());
        } else {
            const Program* program = layerRenderer->renderSurfaceProgram();
            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, -1, -1, -1);
        }
    }
}
示例#12
0
bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const IntRect& touchArea, IntPoint& adjustedPoint)
{
    FrameView* view = geom.node()->document()->view();
    FloatQuad quad = geom.quad();

    if (quad.isRectilinear()) {
        IntRect contentBounds = geom.boundingBox();
        // Convert from frame coordinates to window coordinates.
        IntRect bounds = view->contentsToWindow(contentBounds);
        if (bounds.contains(touchPoint)) {
            adjustedPoint = touchPoint;
            return true;
        }
        if (bounds.intersects(touchArea)) {
            bounds.intersect(touchArea);
            adjustedPoint = bounds.center();
            return true;
        }
        return false;
    }

    // The following code tries to adjust the point to place inside a both the touchArea and the non-rectilinear quad.
    // FIXME: This will return the point inside the touch area that is the closest to the quad center, but does not
    // guarantee that the point will be inside the quad. Corner-cases exist where the quad will intersect but this
    // will fail to adjust the point to somewhere in the intersection.

    // Convert quad from content to window coordinates.
    FloatPoint p1 = contentsToWindow(view, quad.p1());
    FloatPoint p2 = contentsToWindow(view, quad.p2());
    FloatPoint p3 = contentsToWindow(view, quad.p3());
    FloatPoint p4 = contentsToWindow(view, quad.p4());
    quad = FloatQuad(p1, p2, p3, p4);

    if (quad.containsPoint(touchPoint)) {
        adjustedPoint = touchPoint;
        return true;
    }

    // Pull point towards the center of the element.
    FloatPoint center = quad.center();

    adjustPointToRect(center, touchArea);
    adjustedPoint = roundedIntPoint(center);

    return quad.containsPoint(adjustedPoint);
}
示例#13
0
static FloatRect toNormalizedRect(const FloatRect& absoluteRect, const RenderObject* renderer, FloatRect& containerBoundingBox)
{
    ASSERT(renderer);

    const RenderObject* container = renderer->container();
    if (!container) {
        containerBoundingBox = FloatRect();
        return FloatRect();
    }

    FloatRect normalizedRect = absoluteRect;
    FloatRect containerRect = container->absoluteBoundingBoxRect();
    containerBoundingBox = containerRect;

    // For RenderBoxes we want to normalize by the max layout overflow size instead of only the visible bounding box.
    // Quads and their enclosing bounding boxes need to be used in order to keep results transform-friendly.
    if (container->isBox()) {
        const RenderBox* containerBox = toRenderBox(container);
        FloatPoint scrolledOrigin;

        // For overflow:scroll we need to get where the actual origin is independently of the scroll.
        if (container->hasOverflowClip())
            scrolledOrigin = -IntPoint(containerBox->scrolledContentOffset());

        FloatRect overflowRect(scrolledOrigin, containerBox->maxLayoutOverflow());
        containerRect = containerBox->localToAbsoluteQuad(FloatQuad(overflowRect), false).enclosingBoundingBox();
    }

    if (containerRect.isEmpty())
        return FloatRect();

    // Make the coordinates relative to the container enclosing bounding box.
    // Since we work with rects enclosing quad unions this is still transform-friendly.
    normalizedRect.moveBy(-containerRect.location());

    // Fixed positions do not make sense in this coordinate system, but need to leave consistent tickmarks.
    // So, use their position when the view is not scrolled, like an absolute position.
    if (renderer->style()->position() == FixedPosition && container->isRenderView())
        normalizedRect.move(-toRenderView(container)->frameView()->scrollOffsetForFixedPosition());

    normalizedRect.scale(1 / containerRect.width(), 1 / containerRect.height());

    return normalizedRect;
}
示例#14
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.

    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;
}
示例#15
0
static inline Region computeOcclusionBehindLayer(const LayerType* layer, const TransformationMatrix& transform, bool usePaintTracking)
{
    Region opaqueRegion;

    FloatQuad unoccludedQuad = transform.mapQuad(FloatQuad(layer->visibleLayerRect()));
    bool isPaintedAxisAligned = unoccludedQuad.isRectilinear();
    if (!isPaintedAxisAligned)
        return opaqueRegion;

    if (layer->opaque())
        opaqueRegion = enclosedIntRect(unoccludedQuad.boundingBox());
    else if (usePaintTracking && transform.isIdentity())
        opaqueRegion = layer->opaqueContentsRegion();
    else if (usePaintTracking) {
        Region contentRegion = layer->opaqueContentsRegion();
        Vector<IntRect> contentRects = contentRegion.rects();
        for (size_t i = 0; i < contentRects.size(); ++i)
            opaqueRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(contentRects[i]))));
    }
    return opaqueRegion;
}
示例#16
0
FloatRect RenderGeometryMap::absoluteRect(const FloatRect& rect) const
{
    FloatRect result;
    
    if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep()) {
        result = rect;
        result.move(m_accumulatedOffset);
    } else {
        TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
        mapToAbsolute(transformState);
        result = transformState.lastPlanarQuad().boundingBox();
    }

#if !ASSERT_DISABLED
    FloatRect rendererMappedResult = m_mapping.last().m_renderer->localToAbsoluteQuad(rect).boundingBox();
    // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>.
    // Taking FloatQuad bounds avoids spurious assertions because of that.
    ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox()));
#endif

    return result;
}
示例#17
0
FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect,
                                            const RenderBox* container) const {
  FloatRect result;

  if (!hasTransformStep() && !hasNonUniformStep() &&
      (!container ||
       (m_mapping.size() && container == m_mapping[0].m_renderer))) {
    result = rect;
    result.move(m_accumulatedOffset);
  } else {
    TransformState transformState(TransformState::ApplyTransformDirection,
                                  rect.center(), rect);
    mapToContainer(transformState, container);
    result = transformState.lastPlanarQuad().boundingBox();
  }

#if ENABLE(ASSERT)
  if (m_mapping.size() > 0) {
    const RenderObject* lastRenderer = m_mapping.last().m_renderer;

    // Bounds for invisible layers are intentionally not calculated, and are
    // therefore not necessarily expected to be correct here. This is ok,
    // because they will be recomputed if the layer becomes visible.
    FloatRect rendererMappedResult =
        lastRenderer
            ->localToContainerQuad(rect, container, m_mapCoordinatesFlags)
            .boundingBox();

    // Inspector creates renderers with negative width
    // <https://bugs.webkit.org/show_bug.cgi?id=87194>. Taking FloatQuad bounds
    // avoids spurious assertions because of that.
    ASSERT(enclosingIntRect(rendererMappedResult) ==
           enclosingIntRect(FloatQuad(result).boundingBox()));
  }
#endif

  return result;
}
示例#18
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;
}
示例#19
0
FloatQuad RenderGeometryMap::mapToContainer(const FloatRect& rect, const RenderLayerModelObject* container) const
{
    FloatRect result;
    
    if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_renderer))) {
        result = rect;
        result.move(m_accumulatedOffset);
    } else {
        TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect);
        mapToContainer(transformState, container);
        result = transformState.lastPlanarQuad().boundingBox();
    }

#if !ASSERT_DISABLED
    FloatRect rendererMappedResult = m_mapping.last().m_renderer->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox();
    // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>.
    // Taking FloatQuad bounds avoids spurious assertions because of that.
    ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox()));
//    if (enclosingIntRect(rendererMappedResult) != enclosingIntRect(FloatQuad(result).boundingBox()))
//        fprintf(stderr, "Mismatched rects\n");
#endif

    return result;
}
示例#20
0
// The SVG addOutlineRects() method adds rects in local coordinates so the
// default absoluteElementBoundingBoxRect() returns incorrect values for SVG
// objects. Overriding this method provides access to the absolute bounds.
IntRect LayoutSVGModelObject::absoluteElementBoundingBoxRect() const {
  return localToAbsoluteQuad(
             FloatQuad(paintInvalidationRectInLocalSVGCoordinates()))
      .enclosingBoundingBox();
}
static void mapRectToDocumentCoordinates(LayoutObject& layoutObject, LayoutRect& rect)
{
    rect = LayoutRect(layoutObject.localToAbsoluteQuad(FloatQuad(FloatRect(rect)), UseTransforms | ApplyContainerFlip | TraverseDocumentBoundaries).boundingBox());
}
示例#22
0
	const Quad& Quad::draw(const ColorF& color) const
	{
		Siv3DEngine::GetRenderer2D()->addQuad(FloatQuad(p0, p1, p2, p3), color.toFloat4());

		return *this;
	}
示例#23
0
void CCVideoLayerImpl::drawYUV(LayerRendererChromium* layerRenderer) const
{
    const YUVProgram* program = layerRenderer->videoLayerYUVProgram();
    ASSERT(program && program->initialized());

    GraphicsContext3D* context = layerRenderer->context();
    CCVideoLayerImpl::Texture yTexture = m_textures[VideoFrameChromium::yPlane];
    CCVideoLayerImpl::Texture uTexture = m_textures[VideoFrameChromium::uPlane];
    CCVideoLayerImpl::Texture vTexture = m_textures[VideoFrameChromium::vPlane];

    GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE1));
    GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, yTexture.id));
    GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE2));
    GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, uTexture.id));
    GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE3));
    GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, vTexture.id));

    GLC(context, context->useProgram(program->program()));

    float yWidthScaleFactor = static_cast<float>(yTexture.visibleSize.width()) / yTexture.size.width();
    // Arbitrarily take the u sizes because u and v dimensions are identical.
    float uvWidthScaleFactor = static_cast<float>(uTexture.visibleSize.width()) / uTexture.size.width();
    GLC(context, context->uniform1f(program->vertexShader().yWidthScaleFactorLocation(), yWidthScaleFactor));
    GLC(context, context->uniform1f(program->vertexShader().uvWidthScaleFactorLocation(), uvWidthScaleFactor));

    GLC(context, context->uniform1i(program->fragmentShader().yTextureLocation(), 1));
    GLC(context, context->uniform1i(program->fragmentShader().uTextureLocation(), 2));
    GLC(context, context->uniform1i(program->fragmentShader().vTextureLocation(), 3));

    GLC(context, context->uniformMatrix3fv(program->fragmentShader().ccMatrixLocation(), 0, const_cast<float*>(yuv2RGB), 1));
    GLC(context, context->uniform3fv(program->fragmentShader().yuvAdjLocation(), const_cast<float*>(yuvAdjust), 1));

    layerRenderer->drawTexturedQuad(drawTransform(), bounds().width(), bounds().height(), drawOpacity(), FloatQuad(),
                                    program->vertexShader().matrixLocation(),
                                    program->fragmentShader().alphaLocation(),
                                    -1);

    // Reset active texture back to texture 0.
    GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0));
}
示例#24
0
void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle)
{
    auto* scrollContainer = scrollingElement.renderer();
    auto scrollSnapType = scrollingElementStyle.scrollSnapType();
    if (!scrollContainer || scrollSnapType.strictness == ScrollSnapStrictness::None || scrollContainer->view().boxesWithScrollSnapPositions().isEmpty()) {
        scrollableArea.clearHorizontalSnapOffsets();
        scrollableArea.clearVerticalSnapOffsets();
        return;
    }

    Vector<LayoutUnit> verticalSnapOffsets;
    Vector<LayoutUnit> horizontalSnapOffsets;
    Vector<ScrollOffsetRange<LayoutUnit>> verticalSnapOffsetRanges;
    Vector<ScrollOffsetRange<LayoutUnit>> horizontalSnapOffsetRanges;
    HashSet<float> seenVerticalSnapOffsets;
    HashSet<float> seenHorizontalSnapOffsets;
    bool hasHorizontalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::XAxis || scrollSnapType.axis == ScrollSnapAxis::Inline;
    bool hasVerticalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::YAxis || scrollSnapType.axis == ScrollSnapAxis::Block;
    auto maxScrollLeft = scrollingElementBox.scrollWidth() - scrollingElementBox.contentWidth();
    auto maxScrollTop = scrollingElementBox.scrollHeight() - scrollingElementBox.contentHeight();
    LayoutPoint containerScrollOffset(scrollingElementBox.scrollLeft(), scrollingElementBox.scrollTop());

    // The bounds of the scrolling container's snap port, where the top left of the scrolling container's border box is the origin.
    auto scrollSnapPort = computeScrollSnapPortOrAreaRect(scrollingElementBox.paddingBoxRect(), scrollingElementStyle.scrollPadding(), InsetOrOutset::Inset);
#if !LOG_DISABLED
    LOG(Scrolling, "Computing scroll snap offsets in snap port: %s", snapPortOrAreaToString(scrollSnapPort).utf8().data());
#endif
    for (auto* child : scrollContainer->view().boxesWithScrollSnapPositions()) {
        if (child->findEnclosingScrollableContainer() != scrollContainer)
            continue;

        // The bounds of the child element's snap area, where the top left of the scrolling container's border box is the origin.
        // The snap area is the bounding box of the child element's border box, after applying transformations.
        auto scrollSnapArea = LayoutRect(child->localToContainerQuad(FloatQuad(child->borderBoundingBox()), scrollingElement.renderBox()).boundingBox());
        scrollSnapArea.moveBy(containerScrollOffset);
        scrollSnapArea = computeScrollSnapPortOrAreaRect(scrollSnapArea, child->style().scrollSnapMargin(), InsetOrOutset::Outset);
#if !LOG_DISABLED
        LOG(Scrolling, "    Considering scroll snap area: %s", snapPortOrAreaToString(scrollSnapArea).utf8().data());
#endif
        auto alignment = child->style().scrollSnapAlign();
        if (hasHorizontalSnapOffsets && alignment.x != ScrollSnapAxisAlignType::None) {
            auto absoluteScrollOffset = clampTo<LayoutUnit>(computeScrollSnapAlignOffset(scrollSnapArea.x(), scrollSnapArea.width(), alignment.x) - computeScrollSnapAlignOffset(scrollSnapPort.x(), scrollSnapPort.width(), alignment.x), 0, maxScrollLeft);
            if (!seenHorizontalSnapOffsets.contains(absoluteScrollOffset)) {
                seenHorizontalSnapOffsets.add(absoluteScrollOffset);
                horizontalSnapOffsets.append(absoluteScrollOffset);
            }
        }
        if (hasVerticalSnapOffsets && alignment.y != ScrollSnapAxisAlignType::None) {
            auto absoluteScrollOffset = clampTo<LayoutUnit>(computeScrollSnapAlignOffset(scrollSnapArea.y(), scrollSnapArea.height(), alignment.y) - computeScrollSnapAlignOffset(scrollSnapPort.y(), scrollSnapPort.height(), alignment.y), 0, maxScrollTop);
            if (!seenVerticalSnapOffsets.contains(absoluteScrollOffset)) {
                seenVerticalSnapOffsets.add(absoluteScrollOffset);
                verticalSnapOffsets.append(absoluteScrollOffset);
            }
        }
    }

    if (!horizontalSnapOffsets.isEmpty()) {
        adjustAxisSnapOffsetsForScrollExtent(horizontalSnapOffsets, maxScrollLeft);
#if !LOG_DISABLED
        LOG(Scrolling, " => Computed horizontal scroll snap offsets: %s", snapOffsetsToString(horizontalSnapOffsets).utf8().data());
        LOG(Scrolling, " => Computed horizontal scroll snap offset ranges: %s", snapOffsetRangesToString(horizontalSnapOffsetRanges).utf8().data());
#endif
        if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity)
            computeAxisProximitySnapOffsetRanges(horizontalSnapOffsets, horizontalSnapOffsetRanges, scrollSnapPort.width());

        scrollableArea.setHorizontalSnapOffsets(horizontalSnapOffsets);
        scrollableArea.setHorizontalSnapOffsetRanges(horizontalSnapOffsetRanges);
    } else
        scrollableArea.clearHorizontalSnapOffsets();

    if (!verticalSnapOffsets.isEmpty()) {
        adjustAxisSnapOffsetsForScrollExtent(verticalSnapOffsets, maxScrollTop);
#if !LOG_DISABLED
        LOG(Scrolling, " => Computed vertical scroll snap offsets: %s", snapOffsetsToString(verticalSnapOffsets).utf8().data());
        LOG(Scrolling, " => Computed vertical scroll snap offset ranges: %s", snapOffsetRangesToString(verticalSnapOffsetRanges).utf8().data());
#endif
        if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity)
            computeAxisProximitySnapOffsetRanges(verticalSnapOffsets, verticalSnapOffsetRanges, scrollSnapPort.height());

        scrollableArea.setVerticalSnapOffsets(verticalSnapOffsets);
        scrollableArea.setVerticalSnapOffsetRanges(verticalSnapOffsetRanges);
    } else
        scrollableArea.clearVerticalSnapOffsets();
}
示例#25
0
void CCQuadCuller::cullOccludedQuads(CCQuadList& quadList, bool haveDamageRect, const FloatRect& damageRect, CCOverdrawCounts* overdrawMetrics)
{
    if (!quadList.size())
        return;

    CCQuadList culledList;
    culledList.reserveCapacity(quadList.size());

    Region opaqueCoverageThusFar;

    for (int i = quadList.size() - 1; i >= 0; --i) {
        CCDrawQuad* drawQuad = quadList[i].get();

        FloatRect floatTransformedRect = drawQuad->quadTransform().mapRect(FloatRect(drawQuad->quadRect()));
        if (haveDamageRect)
            floatTransformedRect.intersect(damageRect);
        // Inflate rect to be tested to stay conservative.
        IntRect transformedQuadRect(enclosingIntRect(floatTransformedRect));

        IntRect transformedVisibleQuadRect = rectSubtractRegion(opaqueCoverageThusFar, transformedQuadRect);
        bool keepQuad = !transformedVisibleQuadRect.isEmpty();

        // See if we can reduce the number of pixels to draw by reducing the size of the draw
        // quad - we do this by changing its visible rect.
        bool didReduceQuadSize = false;
        if (keepQuad) {
            if (transformedVisibleQuadRect != transformedQuadRect && drawQuad->isLayerAxisAlignedIntRect()) {
                drawQuad->setQuadVisibleRect(drawQuad->quadTransform().inverse().mapRect(transformedVisibleQuadRect));
                didReduceQuadSize = true;
            }

            // When adding rect to opaque region, deflate it to stay conservative.
            if (drawQuad->isLayerAxisAlignedIntRect() && !drawQuad->opaqueRect().isEmpty()) {
                FloatRect floatOpaqueRect = drawQuad->quadTransform().mapRect(FloatRect(drawQuad->opaqueRect()));
                opaqueCoverageThusFar.unite(Region(enclosedIntRect(floatOpaqueRect)));
            }

            culledList.append(quadList[i].release());
        }

        if (overdrawMetrics) {
            TRACE_EVENT("CCQuadCuller::cullOccludedQuads_OverdrawMetrics", 0, 0);
            // We compute the area of the transformed quad, as this should be in pixels.
            float area = quadArea(drawQuad->quadTransform().mapQuad(FloatQuad(drawQuad->quadRect())));
            if (keepQuad) {
                if (didReduceQuadSize) {
                    float visibleQuadRectArea = quadArea(drawQuad->quadTransform().mapQuad(FloatQuad(drawQuad->quadVisibleRect())));
                    overdrawMetrics->m_pixelsCulled += area - visibleQuadRectArea;
                    area = visibleQuadRectArea;
                }
                IntRect visibleOpaqueRect(drawQuad->quadVisibleRect());
                visibleOpaqueRect.intersect(drawQuad->opaqueRect());
                FloatQuad visibleOpaqueQuad = drawQuad->quadTransform().mapQuad(FloatQuad(visibleOpaqueRect));
                float opaqueArea = quadArea(visibleOpaqueQuad);
                overdrawMetrics->m_pixelsDrawnOpaque += opaqueArea;
                overdrawMetrics->m_pixelsDrawnTransparent += area - opaqueArea;
            } else
                overdrawMetrics->m_pixelsCulled += area;
        }
    }
    quadList.clear(); // Release anything that remains.

    culledList.reverse();
    quadList.swap(culledList);
}
// The SVG addFocusRingRects() method adds rects in local coordinates so the default absoluteFocusRingQuads
// returns incorrect values for SVG objects. Overriding this method provides access to the absolute bounds.
void RenderSVGModelObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
{
    quads.append(localToAbsoluteQuad(FloatQuad(repaintRectInLocalCoordinates())));
}
示例#27
0
// called from void RenderLayerCompositor::flushPendingLayerChanges
void GraphicsLayerClutter::flushCompositingState(const FloatRect& clipRect)
{
    TransformState state(TransformState::UnapplyInverseTransformDirection, FloatQuad(clipRect));
    recursiveCommitChanges(state);
}
示例#28
0
void ViewPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo)
{
    if (paintInfo.skipRootBackground())
        return;

    // This function overrides background painting for the LayoutView.
    // View background painting is special in the following ways:
    // 1. The view paints background for the root element, the background positioning respects
    //    the positioning and transformation of the root element.
    // 2. CSS background-clip is ignored, the background layers always expand to cover the whole
    //    canvas. None of the stacking context effects (except transformation) on the root element
    //    affects the background.
    // 3. The main frame is also responsible for painting the user-agent-defined base background
    //    color. Conceptually it should be painted by the embedder but painting it here allows
    //    culling and pre-blending optimization when possible.

    GraphicsContext& context = paintInfo.context;
    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, m_layoutView, DisplayItem::DocumentBackground, LayoutPoint()))
        return;

    // The background fill rect is the size of the LayoutView's main GraphicsLayer.
    IntRect backgroundRect = pixelSnappedIntRect(m_layoutView.layer()->boundingBoxForCompositing());
    const Document& document = m_layoutView.document();
    const FrameView& frameView = *m_layoutView.frameView();
    bool isMainFrame = !document.ownerElement();
    bool paintsBaseBackground = isMainFrame && !frameView.isTransparent();
    bool shouldClearCanvas = paintsBaseBackground && (document.settings() && document.settings()->shouldClearDocumentBackground());
    Color baseBackgroundColor = paintsBaseBackground ? frameView.baseBackgroundColor() : Color();
    Color rootBackgroundColor = m_layoutView.style()->visitedDependentColor(CSSPropertyBackgroundColor);
    const LayoutObject* rootObject = document.documentElement() ? document.documentElement()->layoutObject() : nullptr;

    LayoutObjectDrawingRecorder recorder(context, m_layoutView, DisplayItem::DocumentBackground, backgroundRect, LayoutPoint());

    // Special handling for print economy mode.
    bool forceBackgroundToWhite = BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(m_layoutView.styleRef(), document);
    if (forceBackgroundToWhite) {
        // If for any reason the view background is not transparent, paint white instead, otherwise keep transparent as is.
        if (paintsBaseBackground || rootBackgroundColor.alpha() || m_layoutView.style()->backgroundLayers().image())
            context.fillRect(backgroundRect, Color::white, SkXfermode::kSrc_Mode);
        return;
    }

    // Compute the enclosing rect of the view, in root element space.
    //
    // For background colors we can simply paint the document rect in the default space.
    // However for background image, the root element transform applies. The strategy is to apply
    // root element transform on the context and issue draw commands in the local space, therefore
    // we need to apply inverse transform on the document rect to get to the root element space.
    bool backgroundRenderable = true;
    TransformationMatrix transform;
    IntRect paintRect = backgroundRect;
    if (!rootObject || !rootObject->isBox()) {
        backgroundRenderable = false;
    } else if (rootObject->hasLayer()) {
        const PaintLayer& rootLayer = *toLayoutBoxModelObject(rootObject)->layer();
        LayoutPoint offset;
        rootLayer.convertToLayerCoords(nullptr, offset);
        transform.translate(offset.x(), offset.y());
        transform.multiply(rootLayer.renderableTransform(paintInfo.globalPaintFlags()));

        if (!transform.isInvertible()) {
            backgroundRenderable = false;
        } else {
            bool isClamped;
            paintRect = transform.inverse().projectQuad(FloatQuad(backgroundRect), &isClamped).enclosingBoundingBox();
            backgroundRenderable = !isClamped;
        }
    }

    if (!backgroundRenderable) {
        if (baseBackgroundColor.alpha())
            context.fillRect(backgroundRect, baseBackgroundColor, shouldClearCanvas ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode);
        else if (shouldClearCanvas)
            context.fillRect(backgroundRect, Color(), SkXfermode::kClear_Mode);
        return;
    }

    BoxPainter::FillLayerOcclusionOutputList reversedPaintList;
    bool shouldDrawBackgroundInSeparateBuffer = BoxPainter(m_layoutView).calculateFillLayerOcclusionCulling(reversedPaintList, m_layoutView.style()->backgroundLayers());
    ASSERT(reversedPaintList.size());

    // If the root background color is opaque, isolation group can be skipped because the canvas
    // will be cleared by root background color.
    if (!rootBackgroundColor.hasAlpha())
        shouldDrawBackgroundInSeparateBuffer = false;

    // We are going to clear the canvas with transparent pixels, isolation group can be skipped.
    if (!baseBackgroundColor.alpha() && shouldClearCanvas)
        shouldDrawBackgroundInSeparateBuffer = false;

    if (shouldDrawBackgroundInSeparateBuffer) {
        if (baseBackgroundColor.alpha())
            context.fillRect(backgroundRect, baseBackgroundColor, shouldClearCanvas ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode);
        context.beginLayer();
    }

    Color combinedBackgroundColor = shouldDrawBackgroundInSeparateBuffer ? rootBackgroundColor : baseBackgroundColor.blend(rootBackgroundColor);
    if (combinedBackgroundColor.alpha()) {
        if (!combinedBackgroundColor.hasAlpha() && RuntimeEnabledFeatures::slimmingPaintV2Enabled())
            recorder.setKnownToBeOpaque();
        context.fillRect(backgroundRect, combinedBackgroundColor, (shouldDrawBackgroundInSeparateBuffer || shouldClearCanvas) ? SkXfermode::kSrc_Mode : SkXfermode::kSrcOver_Mode);
    } else if (shouldClearCanvas && !shouldDrawBackgroundInSeparateBuffer) {
        context.fillRect(backgroundRect, Color(), SkXfermode::kClear_Mode);
    }

    for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); ++it) {
        ASSERT((*it)->clip() == BorderFillBox);

        bool shouldPaintInViewportSpace = (*it)->attachment() == FixedBackgroundAttachment;
        if (shouldPaintInViewportSpace) {
            BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(LayoutRect::infiniteIntRect()), BackgroundBleedNone);
        } else {
            context.save();
            // TODO(trchen): We should be able to handle 3D-transformed root
            // background with slimming paint by using transform display items.
            context.concatCTM(transform.toAffineTransform());
            BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(paintRect), BackgroundBleedNone);
            context.restore();
        }
    }

    if (shouldDrawBackgroundInSeparateBuffer)
        context.endLayer();
}
示例#29
0
void CCTiledLayerImpl::appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuadsData)
{
    const IntRect& contentRect = visibleContentRect();

    if (!m_tiler || m_tiler->hasEmptyBounds() || contentRect.isEmpty())
        return;

    CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState());
    appendDebugBorderQuad(quadSink, sharedQuadState, appendQuadsData);

    int left, top, right, bottom;
    m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom);

    if (hasDebugBorders()) {
        for (int j = top; j <= bottom; ++j) {
            for (int i = left; i <= right; ++i) {
                DrawableTile* tile = tileAt(i, j);
                IntRect tileRect = m_tiler->tileBounds(i, j);
                SkColor borderColor;

                if (m_skipsDraw || !tile || !tile->resourceId())
                    borderColor = SkColorSetARGB(debugTileBorderAlpha, debugTileBorderMissingTileColorRed, debugTileBorderMissingTileColorGreen, debugTileBorderMissingTileColorBlue);
                else
                    borderColor = SkColorSetARGB(debugTileBorderAlpha, debugTileBorderColorRed, debugTileBorderColorGreen, debugTileBorderColorBlue);
                quadSink.append(CCDebugBorderDrawQuad::create(sharedQuadState, tileRect, borderColor, debugTileBorderWidth).PassAs<CCDrawQuad>(), appendQuadsData);
            }
        }
    }

    if (m_skipsDraw)
        return;

    for (int j = top; j <= bottom; ++j) {
        for (int i = left; i <= right; ++i) {
            DrawableTile* tile = tileAt(i, j);
            IntRect tileRect = m_tiler->tileBounds(i, j);
            IntRect displayRect = tileRect;
            tileRect.intersect(contentRect);

            // Skip empty tiles.
            if (tileRect.isEmpty())
                continue;

            if (!tile || !tile->resourceId()) {
                if (drawCheckerboardForMissingTiles()) {
                    SkColor defaultColor = SkColorSetRGB(defaultCheckerboardColorRed, defaultCheckerboardColorGreen, defaultCheckerboardColorBlue);
                    SkColor evictedColor = SkColorSetRGB(debugTileEvictedCheckerboardColorRed, debugTileEvictedCheckerboardColorGreen, debugTileEvictedCheckerboardColorBlue);
                    SkColor invalidatedColor = SkColorSetRGB(debugTileInvalidatedCheckerboardColorRed, debugTileEvictedCheckerboardColorGreen, debugTileEvictedCheckerboardColorBlue);

                    SkColor checkerColor;
                    if (hasDebugBorders())
                        checkerColor = tile ? invalidatedColor : evictedColor;
                    else
                        checkerColor = defaultColor;

                    appendQuadsData.hadMissingTiles |= quadSink.append(CCCheckerboardDrawQuad::create(sharedQuadState, tileRect, checkerColor).PassAs<CCDrawQuad>(), appendQuadsData);
                } else
                    appendQuadsData.hadMissingTiles |= quadSink.append(CCSolidColorDrawQuad::create(sharedQuadState, tileRect, backgroundColor()).PassAs<CCDrawQuad>(), appendQuadsData);
                continue;
            }

            IntRect tileOpaqueRect = tile->opaqueRect();
            tileOpaqueRect.intersect(contentRect);

            // Keep track of how the top left has moved, so the texture can be
            // offset the same amount.
            IntSize displayOffset = tileRect.minXMinYCorner() - displayRect.minXMinYCorner();
            IntPoint textureOffset = m_tiler->textureOffset(i, j) + displayOffset;
            float tileWidth = static_cast<float>(m_tiler->tileSize().width());
            float tileHeight = static_cast<float>(m_tiler->tileSize().height());
            IntSize textureSize(tileWidth, tileHeight);

            bool clipped = false;
            FloatQuad visibleContentInTargetQuad = CCMathUtil::mapQuad(drawTransform(), FloatQuad(visibleContentRect()), clipped);
            bool isAxisAlignedInTarget = !clipped && visibleContentInTargetQuad.isRectilinear();
            bool useAA = m_tiler->hasBorderTexels() && !isAxisAlignedInTarget;

            bool leftEdgeAA = !i && useAA;
            bool topEdgeAA = !j && useAA;
            bool rightEdgeAA = i == m_tiler->numTilesX() - 1 && useAA;
            bool bottomEdgeAA = j == m_tiler->numTilesY() - 1 && useAA;

            const GC3Dint textureFilter = m_tiler->hasBorderTexels() ? GraphicsContext3D::LINEAR : GraphicsContext3D::NEAREST;
            quadSink.append(CCTileDrawQuad::create(sharedQuadState, tileRect, tileOpaqueRect, tile->resourceId(), textureOffset, textureSize, textureFilter, contentsSwizzled(), leftEdgeAA, topEdgeAA, rightEdgeAA, bottomEdgeAA).PassAs<CCDrawQuad>(), appendQuadsData);
        }
    }
}
示例#30
0
static inline IntRect computeUnoccludedContentRect(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const IntRect& scissorRect, const Region& occlusion)
{
    if (!contentSpaceTransform.isInvertible())
        return contentRect;

    FloatRect transformedRect = contentSpaceTransform.mapRect(FloatRect(contentRect));
    // Take the enclosingIntRect at each step, as we want to contain any unoccluded partial pixels in the resulting IntRect.
    IntRect shrunkRect = rectSubtractRegion(intersection(enclosingIntRect(transformedRect), scissorRect), occlusion);
    bool clamped; // FIXME: projectQuad returns invalid results when a point gets clamped. To be fixed in bug https://bugs.webkit.org/show_bug.cgi?id=80806.
    IntRect unoccludedRect = enclosingIntRect(projectQuad(contentSpaceTransform.inverse(), FloatQuad(FloatRect(shrunkRect)), clamped).boundingBox());
    if (clamped)
        return contentRect;
    // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds.
    return intersection(unoccludedRect, contentRect);
}