blob: 687faa06ffa4decae884749d4af9d0bda318c485 [file] [log] [blame]
/*
* Copyright (C) 2014 Apple, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "AcceleratedCompositingContext.h"
#if USE(TEXTURE_MAPPER_GL)
#include "WebView.h"
#include <WebCore/Document.h>
#include <WebCore/Frame.h>
#include <WebCore/FrameView.h>
#include <WebCore/GraphicsLayerTextureMapper.h>
#include <WebCore/Page.h>
#include <WebCore/Settings.h>
#include <WebCore/SystemInfo.h>
#include <WebCore/TemporaryOpenGLSetting.h>
#include <WebCore/TextureMapperGL.h>
#include <WebCore/TextureMapperLayer.h>
#if USE(OPENGL_ES)
#include <GLES2/gl2.h>
#else
#include <GL/gl.h>
#endif
using namespace WebCore;
AcceleratedCompositingContext::AcceleratedCompositingContext(WebView& webView)
: m_webView(webView)
, m_context(nullptr)
, m_window(0)
, m_layerFlushTimer(*this)
{
}
static IntSize getWebViewSize(WebView& webView)
{
RECT r;
webView.frameRect(&r);
return IntSize(r.right - r.left, r.bottom - r.top);
}
void AcceleratedCompositingContext::initialize()
{
if (m_rootLayer)
return;
IntSize pageSize = getWebViewSize(m_webView);
m_window = m_webView.viewWindow();
if (!m_window)
return;
m_rootLayer = GraphicsLayer::create(nullptr, *this);
m_rootLayer->setDrawsContent(false);
m_rootLayer->setSize(pageSize);
applyDeviceScaleFactor();
// The non-composited contents are a child of the root layer.
m_nonCompositedContentLayer = GraphicsLayer::create(nullptr, *this);
m_nonCompositedContentLayer->setDrawsContent(true);
m_nonCompositedContentLayer->setContentsOpaque(!m_webView.transparent());
m_nonCompositedContentLayer->setSize(pageSize);
if (core(&m_webView)->settings().acceleratedDrawingEnabled())
m_nonCompositedContentLayer->setAcceleratesDrawing(true);
#ifndef NDEBUG
m_rootLayer->setName("Root layer");
m_nonCompositedContentLayer->setName("Non-composited content");
#endif
m_rootLayer->addChild(*m_nonCompositedContentLayer);
m_nonCompositedContentLayer->setNeedsDisplay();
// The creation of the TextureMapper needs an active OpenGL context.
if (!m_context)
m_context = GLContext::createContextForWindow(m_window);
if (!m_context)
return;
m_context->makeContextCurrent();
m_textureMapper = TextureMapperGL::create();
downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().setTextureMapper(m_textureMapper.get());
scheduleLayerFlush();
}
AcceleratedCompositingContext::~AcceleratedCompositingContext()
{
stopAnyPendingLayerFlush();
}
void AcceleratedCompositingContext::stopAnyPendingLayerFlush()
{
m_layerFlushTimer.stop();
}
bool AcceleratedCompositingContext::enabled()
{
return m_window && m_rootLayer && m_textureMapper;
}
bool AcceleratedCompositingContext::prepareForRendering()
{
if (!enabled())
return false;
if (!m_context)
return false;
if (!m_context->makeContextCurrent())
return false;
return true;
}
bool AcceleratedCompositingContext::startedAnimation(WebCore::GraphicsLayer* layer)
{
if (!layer)
return false;
return downcast<GraphicsLayerTextureMapper>(*layer).layer().descendantsOrSelfHaveRunningAnimations();
}
void AcceleratedCompositingContext::applyDeviceScaleFactor()
{
if (!m_rootLayer)
return;
const FloatSize& size = m_rootLayer->size();
TransformationMatrix m;
m.scale(deviceScaleFactor());
// Center view
double tx = (size.width() - size.width() / deviceScaleFactor()) / 2.0;
double ty = (size.height() - size.height() / deviceScaleFactor()) / 2.0;
m.translate(tx, ty);
m_rootLayer->setTransform(m);
}
void AcceleratedCompositingContext::compositeLayersToContext(CompositePurpose purpose)
{
if (!prepareForRendering())
return;
RECT r;
if (!::GetClientRect(m_window, &r))
return;
IntSize windowSize(r.right, r.bottom);
glViewport(0, 0, windowSize.width(), windowSize.height());
if (purpose == ForResize) {
TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE);
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
}
m_textureMapper->beginPainting();
downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().paint();
m_fpsCounter.updateFPSAndDisplay(*m_textureMapper);
m_textureMapper->endPainting();
m_context->swapBuffers();
}
void AcceleratedCompositingContext::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
{
prepareForRendering();
if (!graphicsLayer) {
stopAnyPendingLayerFlush();
m_rootLayer = nullptr;
m_nonCompositedContentLayer = nullptr;
m_textureMapper = nullptr;
return;
}
// Add the accelerated layer tree hierarchy.
initialize();
if (!m_window)
return;
m_nonCompositedContentLayer->removeAllChildren();
m_nonCompositedContentLayer->addChild(*graphicsLayer);
stopAnyPendingLayerFlush();
scheduleLayerFlush();
}
void AcceleratedCompositingContext::setNonCompositedContentsNeedDisplay(const IntRect& rect)
{
if (!m_rootLayer)
return;
if (rect.isEmpty()) {
m_rootLayer->setNeedsDisplay();
return;
}
m_nonCompositedContentLayer->setNeedsDisplayInRect(rect);
scheduleLayerFlush();
}
void AcceleratedCompositingContext::resizeRootLayer(const IntSize& newSize)
{
if (!enabled())
return;
if (m_rootLayer->size() == newSize)
return;
m_rootLayer->setSize(newSize);
applyDeviceScaleFactor();
// If the newSize exposes new areas of the non-composited content a setNeedsDisplay is needed
// for those newly exposed areas.
FloatSize oldSize = m_nonCompositedContentLayer->size();
m_nonCompositedContentLayer->setSize(newSize);
if (newSize.width() > oldSize.width()) {
float height = std::min(static_cast<float>(newSize.height()), oldSize.height());
m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(oldSize.width(), 0, newSize.width() - oldSize.width(), height));
}
if (newSize.height() > oldSize.height())
m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height()));
m_nonCompositedContentLayer->setNeedsDisplayInRect(IntRect(IntPoint(), newSize));
compositeLayersToContext(ForResize);
scheduleLayerFlush();
}
void AcceleratedCompositingContext::scrollNonCompositedContents(const IntRect& scrollRect, const IntSize& /* scrollOffset */)
{
m_nonCompositedContentLayer->setNeedsDisplay();
scheduleLayerFlush();
}
void AcceleratedCompositingContext::scheduleLayerFlush()
{
if (!enabled())
return;
if (m_layerFlushTimer.isActive())
return;
m_layerFlushTimer.startOneShot(50_ms);
}
bool AcceleratedCompositingContext::flushPendingLayerChanges()
{
FrameView* frameView = core(&m_webView)->mainFrame().view();
m_rootLayer->flushCompositingStateForThisLayerOnly();
m_nonCompositedContentLayer->flushCompositingStateForThisLayerOnly();
if (!frameView->flushCompositingStateIncludingSubframes())
return false;
downcast<GraphicsLayerTextureMapper>(*m_rootLayer).updateBackingStoreIncludingSubLayers();
return true;
}
bool AcceleratedCompositingContext::flushPendingLayerChangesSoon()
{
scheduleLayerFlush();
return true;
}
void AcceleratedCompositingContext::flushAndRenderLayers()
{
if (!enabled())
return;
Frame& frame = core(&m_webView)->mainFrame();
if (!frame.contentRenderer() || !frame.view())
return;
frame.view()->updateLayoutAndStyleIfNeededRecursive();
if (!enabled())
return;
if (m_context && !m_context->makeContextCurrent())
return;
if (!flushPendingLayerChanges())
return;
compositeLayersToContext();
}
void AcceleratedCompositingContext::layerFlushTimerFired()
{
flushAndRenderLayers();
// In case an animation is running, we should flush again soon.
if (startedAnimation(m_rootLayer.get()))
scheduleLayerFlush();
}
void AcceleratedCompositingContext::paintContents(const GraphicsLayer*, GraphicsContext& context, const FloatRect& rectToPaint, GraphicsLayerPaintBehavior)
{
context.save();
context.clip(rectToPaint);
core(&m_webView)->mainFrame().view()->paint(context, enclosingIntRect(rectToPaint));
context.restore();
}
float AcceleratedCompositingContext::deviceScaleFactor() const
{
return m_webView.deviceScaleFactor();
}
#endif // USE(TEXTURE_MAPPER_GL)