| // Copyright 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/render_surface_impl.h" |
| |
| #include <algorithm> |
| |
| #include "base/logging.h" |
| #include "base/stringprintf.h" |
| #include "cc/damage_tracker.h" |
| #include "cc/debug_border_draw_quad.h" |
| #include "cc/debug_colors.h" |
| #include "cc/delegated_renderer_layer_impl.h" |
| #include "cc/layer_impl.h" |
| #include "cc/math_util.h" |
| #include "cc/quad_sink.h" |
| #include "cc/render_pass.h" |
| #include "cc/render_pass_draw_quad.h" |
| #include "cc/render_pass_sink.h" |
| #include "cc/shared_quad_state.h" |
| #include "third_party/skia/include/core/SkImageFilter.h" |
| #include "ui/gfx/rect_conversions.h" |
| #include "ui/gfx/transform.h" |
| |
| namespace cc { |
| |
| RenderSurfaceImpl::RenderSurfaceImpl(LayerImpl* owningLayer) |
| : m_owningLayer(owningLayer) |
| , m_surfacePropertyChanged(false) |
| , m_drawOpacity(1) |
| , m_drawOpacityIsAnimating(false) |
| , m_targetSurfaceTransformsAreAnimating(false) |
| , m_screenSpaceTransformsAreAnimating(false) |
| , m_isClipped(false) |
| , m_nearestAncestorThatMovesPixels(0) |
| , m_targetRenderSurfaceLayerIndexHistory(0) |
| , m_currentLayerIndexHistory(0) |
| { |
| m_damageTracker = DamageTracker::create(); |
| } |
| |
| RenderSurfaceImpl::~RenderSurfaceImpl() |
| { |
| } |
| |
| gfx::RectF RenderSurfaceImpl::drawableContentRect() const |
| { |
| gfx::RectF drawableContentRect = MathUtil::mapClippedRect(m_drawTransform, m_contentRect); |
| if (m_owningLayer->hasReplica()) |
| drawableContentRect.Union(MathUtil::mapClippedRect(m_replicaDrawTransform, m_contentRect)); |
| |
| return drawableContentRect; |
| } |
| |
| std::string RenderSurfaceImpl::name() const |
| { |
| return base::StringPrintf("RenderSurfaceImpl(id=%i,owner=%s)", m_owningLayer->id(), m_owningLayer->debugName().data()); |
| } |
| |
| static std::string indentString(int indent) |
| { |
| std::string str; |
| for (int i = 0; i != indent; ++i) |
| str.append(" "); |
| return str; |
| } |
| |
| void RenderSurfaceImpl::dumpSurface(std::string* str, int indent) const |
| { |
| std::string indentStr = indentString(indent); |
| str->append(indentStr); |
| base::StringAppendF(str, "%s\n", name().data()); |
| |
| indentStr.append(" "); |
| str->append(indentStr); |
| base::StringAppendF(str, "contentRect: (%d, %d, %d, %d)\n", m_contentRect.x(), m_contentRect.y(), m_contentRect.width(), m_contentRect.height()); |
| |
| str->append(indentStr); |
| base::StringAppendF(str, "drawTransform: %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n", |
| m_drawTransform.matrix().getDouble(0, 0), m_drawTransform.matrix().getDouble(0, 1), m_drawTransform.matrix().getDouble(0, 2), m_drawTransform.matrix().getDouble(0, 3), |
| m_drawTransform.matrix().getDouble(1, 0), m_drawTransform.matrix().getDouble(1, 1), m_drawTransform.matrix().getDouble(1, 2), m_drawTransform.matrix().getDouble(1, 3), |
| m_drawTransform.matrix().getDouble(2, 0), m_drawTransform.matrix().getDouble(2, 1), m_drawTransform.matrix().getDouble(2, 2), m_drawTransform.matrix().getDouble(2, 3), |
| m_drawTransform.matrix().getDouble(3, 0), m_drawTransform.matrix().getDouble(3, 1), m_drawTransform.matrix().getDouble(3, 2), m_drawTransform.matrix().getDouble(3, 3)); |
| |
| str->append(indentStr); |
| base::StringAppendF(str, "damageRect is pos(%f, %f), size(%f, %f)\n", |
| m_damageTracker->currentDamageRect().x(), m_damageTracker->currentDamageRect().y(), |
| m_damageTracker->currentDamageRect().width(), m_damageTracker->currentDamageRect().height()); |
| } |
| |
| int RenderSurfaceImpl::owningLayerId() const |
| { |
| return m_owningLayer ? m_owningLayer->id() : 0; |
| } |
| |
| |
| void RenderSurfaceImpl::setClipRect(const gfx::Rect& clipRect) |
| { |
| if (m_clipRect == clipRect) |
| return; |
| |
| m_surfacePropertyChanged = true; |
| m_clipRect = clipRect; |
| } |
| |
| bool RenderSurfaceImpl::contentsChanged() const |
| { |
| return !m_damageTracker->currentDamageRect().IsEmpty(); |
| } |
| |
| void RenderSurfaceImpl::setContentRect(const gfx::Rect& contentRect) |
| { |
| if (m_contentRect == contentRect) |
| return; |
| |
| m_surfacePropertyChanged = true; |
| m_contentRect = contentRect; |
| } |
| |
| bool RenderSurfaceImpl::surfacePropertyChanged() const |
| { |
| // Surface property changes are tracked as follows: |
| // |
| // - m_surfacePropertyChanged is flagged when the clipRect or contentRect change. As |
| // of now, these are the only two properties that can be affected by descendant layers. |
| // |
| // - all other property changes come from the owning layer (or some ancestor layer |
| // that propagates its change to the owning layer). |
| // |
| DCHECK(m_owningLayer); |
| return m_surfacePropertyChanged || m_owningLayer->layerPropertyChanged(); |
| } |
| |
| bool RenderSurfaceImpl::surfacePropertyChangedOnlyFromDescendant() const |
| { |
| return m_surfacePropertyChanged && !m_owningLayer->layerPropertyChanged(); |
| } |
| |
| void RenderSurfaceImpl::addContributingDelegatedRenderPassLayer(LayerImpl* layer) |
| { |
| DCHECK(std::find(m_layerList.begin(), m_layerList.end(), layer) != m_layerList.end()); |
| DelegatedRendererLayerImpl* delegatedRendererLayer = static_cast<DelegatedRendererLayerImpl*>(layer); |
| m_contributingDelegatedRenderPassLayerList.push_back(delegatedRendererLayer); |
| } |
| |
| void RenderSurfaceImpl::clearLayerLists() |
| { |
| m_layerList.clear(); |
| m_contributingDelegatedRenderPassLayerList.clear(); |
| } |
| |
| static inline gfx::Rect computeClippedRectInTarget(const LayerImpl* owningLayer) |
| { |
| DCHECK(owningLayer->parent()); |
| |
| const LayerImpl* renderTarget = owningLayer->parent()->renderTarget(); |
| const RenderSurfaceImpl* self = owningLayer->renderSurface(); |
| |
| gfx::Rect clippedRectInTarget = self->clipRect(); |
| if (owningLayer->backgroundFilters().hasFilterThatMovesPixels()) { |
| // If the layer has background filters that move pixels, we cannot scissor as tightly. |
| // FIXME: this should be able to be a tighter scissor, perhaps expanded by the filter outsets? |
| clippedRectInTarget = renderTarget->renderSurface()->contentRect(); |
| } else if (clippedRectInTarget.IsEmpty()) { |
| // For surfaces, empty clipRect means that the surface does not clip anything. |
| clippedRectInTarget = renderTarget->renderSurface()->contentRect(); |
| clippedRectInTarget.Intersect(gfx::ToEnclosingRect(self->drawableContentRect())); |
| } else |
| clippedRectInTarget.Intersect(gfx::ToEnclosingRect(self->drawableContentRect())); |
| return clippedRectInTarget; |
| } |
| |
| RenderPass::Id RenderSurfaceImpl::renderPassId() |
| { |
| int layerId = m_owningLayer->id(); |
| int subId = 0; |
| DCHECK(layerId > 0); |
| return RenderPass::Id(layerId, subId); |
| } |
| |
| void RenderSurfaceImpl::appendRenderPasses(RenderPassSink& passSink) |
| { |
| for (size_t i = 0; i < m_contributingDelegatedRenderPassLayerList.size(); ++i) |
| m_contributingDelegatedRenderPassLayerList[i]->appendContributingRenderPasses(passSink); |
| |
| scoped_ptr<RenderPass> pass = RenderPass::Create(); |
| pass->SetNew(renderPassId(), m_contentRect, m_damageTracker->currentDamageRect(), m_screenSpaceTransform); |
| pass->filters = m_owningLayer->filters(); |
| pass->filter = m_owningLayer->filter(); |
| pass->background_filters = m_owningLayer->backgroundFilters(); |
| passSink.appendRenderPass(pass.Pass()); |
| } |
| |
| void RenderSurfaceImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuadsData, bool forReplica, RenderPass::Id renderPassId) |
| { |
| DCHECK(!forReplica || m_owningLayer->hasReplica()); |
| |
| gfx::Rect clippedRectInTarget = computeClippedRectInTarget(m_owningLayer); |
| const gfx::Transform& drawTransform = forReplica ? m_replicaDrawTransform : m_drawTransform; |
| SharedQuadState* sharedQuadState = quadSink.useSharedQuadState(SharedQuadState::Create()); |
| sharedQuadState->SetAll(drawTransform, m_contentRect, clippedRectInTarget, m_clipRect, m_isClipped, m_drawOpacity); |
| |
| if (m_owningLayer->showDebugBorders()) { |
| SkColor color = forReplica ? DebugColors::SurfaceReplicaBorderColor() : DebugColors::SurfaceBorderColor(); |
| float width = forReplica ? DebugColors::SurfaceReplicaBorderWidth(m_owningLayer->layerTreeImpl()) : DebugColors::SurfaceBorderWidth(m_owningLayer->layerTreeImpl()); |
| scoped_ptr<DebugBorderDrawQuad> debugBorderQuad = DebugBorderDrawQuad::Create(); |
| debugBorderQuad->SetNew(sharedQuadState, contentRect(), color, width); |
| quadSink.append(debugBorderQuad.PassAs<DrawQuad>(), appendQuadsData); |
| } |
| |
| // FIXME: By using the same RenderSurfaceImpl for both the content and its reflection, |
| // it's currently not possible to apply a separate mask to the reflection layer |
| // or correctly handle opacity in reflections (opacity must be applied after drawing |
| // both the layer and its reflection). The solution is to introduce yet another RenderSurfaceImpl |
| // to draw the layer and its reflection in. For now we only apply a separate reflection |
| // mask if the contents don't have a mask of their own. |
| LayerImpl* maskLayer = m_owningLayer->maskLayer(); |
| if (maskLayer && (!maskLayer->drawsContent() || maskLayer->bounds().IsEmpty())) |
| maskLayer = 0; |
| |
| if (!maskLayer && forReplica) { |
| maskLayer = m_owningLayer->replicaLayer()->maskLayer(); |
| if (maskLayer && (!maskLayer->drawsContent() || maskLayer->bounds().IsEmpty())) |
| maskLayer = 0; |
| } |
| |
| gfx::RectF maskUVRect(0.0f, 0.0f, 1.0f, 1.0f); |
| if (maskLayer) { |
| // Because the RenderSurface is sized base on the screen footprint, |
| // there can be a scale between the RenderSurface and the owning layer, |
| // as well as the mask. While the mask doesn't have a drawTransform, the |
| // owning layer has it (and should be pure scaling), so use that to |
| // scale the mask to the right size. |
| gfx::Vector2dF maskDrawScale = MathUtil::computeTransform2dScaleComponents(m_owningLayer->drawTransform(), 1.f); |
| float scaleX = contentRect().width() / maskLayer->contentsScaleX() / maskLayer->bounds().width() / maskDrawScale.x(); |
| float scaleY = contentRect().height() / maskLayer->contentsScaleY() / maskLayer->bounds().height() / maskDrawScale.y(); |
| |
| maskUVRect = gfx::RectF(static_cast<float>(contentRect().x()) / contentRect().width() * scaleX, |
| static_cast<float>(contentRect().y()) / contentRect().height() * scaleY, |
| scaleX, |
| scaleY); |
| } |
| |
| ResourceProvider::ResourceId maskResourceId = maskLayer ? maskLayer->contentsResourceId() : 0; |
| gfx::Rect contentsChangedSinceLastFrame = contentsChanged() ? m_contentRect : gfx::Rect(); |
| |
| scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create(); |
| quad->SetNew(sharedQuadState, contentRect(), renderPassId, forReplica, maskResourceId, contentsChangedSinceLastFrame, maskUVRect); |
| quadSink.append(quad.PassAs<DrawQuad>(), appendQuadsData); |
| } |
| |
| } // namespace cc |