diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebKit2/Shared/CoordinatedGraphics | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebKit2/Shared/CoordinatedGraphics')
16 files changed, 3374 insertions, 0 deletions
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedBackingStore.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedBackingStore.cpp new file mode 100644 index 000000000..bb46942a1 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedBackingStore.cpp @@ -0,0 +1,191 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "CoordinatedBackingStore.h" + +#if USE(COORDINATED_GRAPHICS) +#include <WebCore/CoordinatedSurface.h> +#include <WebCore/GraphicsLayer.h> +#include <WebCore/TextureMapper.h> +#include <WebCore/TextureMapperGL.h> + +using namespace WebCore; + +namespace WebKit { + +void CoordinatedBackingStoreTile::swapBuffers(TextureMapper& textureMapper) +{ + if (!m_surface) + return; + + FloatRect tileRect(m_tileRect); + tileRect.scale(1. / m_scale); + bool shouldReset = false; + if (tileRect != rect()) { + setRect(tileRect); + shouldReset = true; + } + RefPtr<BitmapTexture> texture = this->texture(); + if (!texture) { + texture = textureMapper.createTexture(); + setTexture(texture.get()); + shouldReset = true; + } + + if (m_surface->supportsAlpha() == texture->isOpaque()) + shouldReset = true; + + ASSERT(textureMapper.maxTextureSize().width() >= m_tileRect.size().width()); + ASSERT(textureMapper.maxTextureSize().height() >= m_tileRect.size().height()); + if (shouldReset) + texture->reset(m_tileRect.size(), m_surface->supportsAlpha()); + + m_surface->copyToTexture(texture, m_sourceRect, m_surfaceOffset); + m_surface = nullptr; +} + +void CoordinatedBackingStoreTile::setBackBuffer(const IntRect& tileRect, const IntRect& sourceRect, PassRefPtr<CoordinatedSurface> buffer, const IntPoint& offset) +{ + m_sourceRect = sourceRect; + m_tileRect = tileRect; + m_surfaceOffset = offset; + m_surface = buffer; +} + +void CoordinatedBackingStore::createTile(uint32_t id, float scale) +{ + m_tiles.add(id, CoordinatedBackingStoreTile(scale)); + m_scale = scale; +} + +void CoordinatedBackingStore::removeTile(uint32_t id) +{ + ASSERT(m_tiles.contains(id)); + m_tilesToRemove.add(id); +} + +void CoordinatedBackingStore::removeAllTiles() +{ + for (auto& key : m_tiles.keys()) + m_tilesToRemove.add(key); +} + +void CoordinatedBackingStore::updateTile(uint32_t id, const IntRect& sourceRect, const IntRect& tileRect, PassRefPtr<CoordinatedSurface> backBuffer, const IntPoint& offset) +{ + CoordinatedBackingStoreTileMap::iterator it = m_tiles.find(id); + ASSERT(it != m_tiles.end()); + it->value.setBackBuffer(tileRect, sourceRect, backBuffer, offset); +} + +RefPtr<BitmapTexture> CoordinatedBackingStore::texture() const +{ + for (auto& tile : m_tiles.values()) { + RefPtr<BitmapTexture> texture = tile.texture(); + if (texture) + return texture; + } + + return RefPtr<BitmapTexture>(); +} + +void CoordinatedBackingStore::setSize(const FloatSize& size) +{ + m_pendingSize = size; +} + +void CoordinatedBackingStore::paintTilesToTextureMapper(Vector<TextureMapperTile*>& tiles, TextureMapper& textureMapper, const TransformationMatrix& transform, float opacity, const FloatRect& rect) +{ + for (auto& tile : tiles) + tile->paint(textureMapper, transform, opacity, calculateExposedTileEdges(rect, tile->rect())); +} + +TransformationMatrix CoordinatedBackingStore::adjustedTransformForRect(const FloatRect& targetRect) +{ + return TransformationMatrix::rectToRect(rect(), targetRect); +} + +void CoordinatedBackingStore::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) +{ + if (m_tiles.isEmpty()) + return; + ASSERT(!m_size.isZero()); + + Vector<TextureMapperTile*> tilesToPaint; + Vector<TextureMapperTile*> previousTilesToPaint; + + // We have to do this every time we paint, in case the opacity has changed. + FloatRect coveredRect; + for (auto& tile : m_tiles.values()) { + if (!tile.texture()) + continue; + + if (tile.scale() == m_scale) { + tilesToPaint.append(&tile); + coveredRect.unite(tile.rect()); + continue; + } + + // Only show the previous tile if the opacity is high, otherwise effect looks like a bug. + // We show the previous-scale tile anyway if it doesn't intersect with any current-scale tile. + if (opacity < 0.95 && coveredRect.intersects(tile.rect())) + continue; + + previousTilesToPaint.append(&tile); + } + + // targetRect is on the contents coordinate system, so we must compare two rects on the contents coordinate system. + // See TiledBackingStore. + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + + paintTilesToTextureMapper(previousTilesToPaint, textureMapper, adjustedTransform, opacity, rect()); + paintTilesToTextureMapper(tilesToPaint, textureMapper, adjustedTransform, opacity, rect()); +} + +void CoordinatedBackingStore::drawBorder(TextureMapper& textureMapper, const Color& borderColor, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) +{ + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + for (auto& tile : m_tiles.values()) + textureMapper.drawBorder(borderColor, borderWidth, tile.rect(), adjustedTransform); +} + +void CoordinatedBackingStore::drawRepaintCounter(TextureMapper& textureMapper, int repaintCount, const Color& borderColor, const FloatRect& targetRect, const TransformationMatrix& transform) +{ + TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); + for (auto& tile : m_tiles.values()) + textureMapper.drawNumber(repaintCount, borderColor, tile.rect().location(), adjustedTransform); +} + +void CoordinatedBackingStore::commitTileOperations(TextureMapper& textureMapper) +{ + if (!m_pendingSize.isZero()) { + m_size = m_pendingSize; + m_pendingSize = FloatSize(); + } + + for (auto& tileToRemove : m_tilesToRemove) + m_tiles.remove(tileToRemove); + m_tilesToRemove.clear(); + + for (auto& tile : m_tiles.values()) + tile.swapBuffers(textureMapper); +} + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedBackingStore.h b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedBackingStore.h new file mode 100644 index 000000000..166c0a1c7 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedBackingStore.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef CoordinatedBackingStore_h +#define CoordinatedBackingStore_h + +#if USE(COORDINATED_GRAPHICS) + +#include <WebCore/TextureMapper.h> +#include <WebCore/TextureMapperBackingStore.h> +#include <WebCore/TextureMapperTile.h> +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> + + +namespace WebCore { +class CoordinatedSurface; +} + +namespace WebKit { + +class CoordinatedBackingStoreTile : public WebCore::TextureMapperTile { +public: + explicit CoordinatedBackingStoreTile(float scale = 1) + : WebCore::TextureMapperTile(WebCore::FloatRect()) + , m_scale(scale) + { + } + + inline float scale() const { return m_scale; } + void swapBuffers(WebCore::TextureMapper&); + void setBackBuffer(const WebCore::IntRect&, const WebCore::IntRect&, PassRefPtr<WebCore::CoordinatedSurface> buffer, const WebCore::IntPoint&); + +private: + RefPtr<WebCore::CoordinatedSurface> m_surface; + WebCore::IntRect m_sourceRect; + WebCore::IntRect m_tileRect; + WebCore::IntPoint m_surfaceOffset; + float m_scale; +}; + +class CoordinatedBackingStore : public WebCore::TextureMapperBackingStore { +public: + void createTile(uint32_t tileID, float); + void removeTile(uint32_t tileID); + void removeAllTiles(); + void updateTile(uint32_t tileID, const WebCore::IntRect&, const WebCore::IntRect&, PassRefPtr<WebCore::CoordinatedSurface>, const WebCore::IntPoint&); + static Ref<CoordinatedBackingStore> create() { return adoptRef(*new CoordinatedBackingStore); } + void commitTileOperations(WebCore::TextureMapper&); + RefPtr<WebCore::BitmapTexture> texture() const override; + void setSize(const WebCore::FloatSize&); + void paintToTextureMapper(WebCore::TextureMapper&, const WebCore::FloatRect&, const WebCore::TransformationMatrix&, float) override; + void drawBorder(WebCore::TextureMapper&, const WebCore::Color&, float borderWidth, const WebCore::FloatRect&, const WebCore::TransformationMatrix&) override; + void drawRepaintCounter(WebCore::TextureMapper&, int repaintCount, const WebCore::Color&, const WebCore::FloatRect&, const WebCore::TransformationMatrix&) override; + +private: + CoordinatedBackingStore() + : m_scale(1.) + { } + void paintTilesToTextureMapper(Vector<WebCore::TextureMapperTile*>&, WebCore::TextureMapper&, const WebCore::TransformationMatrix&, float, const WebCore::FloatRect&); + WebCore::TransformationMatrix adjustedTransformForRect(const WebCore::FloatRect&); + WebCore::FloatRect rect() const { return WebCore::FloatRect(WebCore::FloatPoint::zero(), m_size); } + + typedef HashMap<uint32_t, CoordinatedBackingStoreTile> CoordinatedBackingStoreTileMap; + CoordinatedBackingStoreTileMap m_tiles; + HashSet<uint32_t> m_tilesToRemove; + // FIXME: m_pendingSize should be removed after the following bug is fixed: https://bugs.webkit.org/show_bug.cgi?id=108294 + WebCore::FloatSize m_pendingSize; + WebCore::FloatSize m_size; + float m_scale; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedBackingStore_h diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsArgumentCoders.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsArgumentCoders.cpp new file mode 100644 index 000000000..9492d826f --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsArgumentCoders.cpp @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2012 Company 100, 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 "config.h" +#include "CoordinatedGraphicsArgumentCoders.h" + +#if USE(COORDINATED_GRAPHICS) +#include "WebCoordinatedSurface.h" +#include "WebCoreArgumentCoders.h" +#include <WebCore/Animation.h> +#include <WebCore/Color.h> +#include <WebCore/CoordinatedGraphicsState.h> +#include <WebCore/FilterOperations.h> +#include <WebCore/FloatPoint3D.h> +#include <WebCore/IdentityTransformOperation.h> +#include <WebCore/IntPoint.h> +#include <WebCore/Length.h> +#include <WebCore/Matrix3DTransformOperation.h> +#include <WebCore/MatrixTransformOperation.h> +#include <WebCore/PerspectiveTransformOperation.h> +#include <WebCore/RotateTransformOperation.h> +#include <WebCore/ScaleTransformOperation.h> +#include <WebCore/SkewTransformOperation.h> +#include <WebCore/SurfaceUpdateInfo.h> +#include <WebCore/TextureMapperAnimation.h> +#include <WebCore/TimingFunction.h> +#include <WebCore/TransformationMatrix.h> +#include <WebCore/TranslateTransformOperation.h> + +using namespace WebCore; +using namespace WebKit; + +namespace IPC { + +void ArgumentCoder<WebCore::FilterOperations>::encode(Encoder& encoder, const WebCore::FilterOperations& filters) +{ + encoder << static_cast<uint32_t>(filters.size()); + for (size_t i = 0; i < filters.size(); ++i) { + const FilterOperation& filter = *filters.at(i); + FilterOperation::OperationType type = filter.type(); + encoder.encodeEnum(type); + switch (type) { + case FilterOperation::GRAYSCALE: + case FilterOperation::SEPIA: + case FilterOperation::SATURATE: + case FilterOperation::HUE_ROTATE: + encoder << static_cast<double>(downcast<BasicColorMatrixFilterOperation>(filter).amount()); + break; + case FilterOperation::INVERT: + case FilterOperation::BRIGHTNESS: + case FilterOperation::CONTRAST: + case FilterOperation::OPACITY: + encoder << static_cast<double>(downcast<BasicComponentTransferFilterOperation>(filter).amount()); + break; + case FilterOperation::BLUR: + ArgumentCoder<Length>::encode(encoder, downcast<BlurFilterOperation>(filter).stdDeviation()); + break; + case FilterOperation::DROP_SHADOW: { + const DropShadowFilterOperation& shadow = downcast<DropShadowFilterOperation>(filter); + ArgumentCoder<IntPoint>::encode(encoder, shadow.location()); + encoder << static_cast<int32_t>(shadow.stdDeviation()); + ArgumentCoder<Color>::encode(encoder, shadow.color()); + break; + } + case FilterOperation::REFERENCE: + case FilterOperation::PASSTHROUGH: + case FilterOperation::DEFAULT: + case FilterOperation::NONE: + break; + } + } +} + +bool ArgumentCoder<WebCore::FilterOperations>::decode(Decoder& decoder, WebCore::FilterOperations& filters) +{ + uint32_t size; + if (!decoder.decode(size)) + return false; + + Vector<RefPtr<FilterOperation> >& operations = filters.operations(); + + for (size_t i = 0; i < size; ++i) { + FilterOperation::OperationType type; + RefPtr<FilterOperation> filter; + if (!decoder.decodeEnum(type)) + return false; + + switch (type) { + case FilterOperation::GRAYSCALE: + case FilterOperation::SEPIA: + case FilterOperation::SATURATE: + case FilterOperation::HUE_ROTATE: { + double value; + if (!decoder.decode(value)) + return false; + filter = BasicColorMatrixFilterOperation::create(value, type); + break; + } + case FilterOperation::INVERT: + case FilterOperation::BRIGHTNESS: + case FilterOperation::CONTRAST: + case FilterOperation::OPACITY: { + double value; + if (!decoder.decode(value)) + return false; + filter = BasicComponentTransferFilterOperation::create(value, type); + break; + } + case FilterOperation::BLUR: { + Length length; + if (!ArgumentCoder<Length>::decode(decoder, length)) + return false; + filter = BlurFilterOperation::create(length); + break; + } + case FilterOperation::DROP_SHADOW: { + IntPoint location; + int32_t stdDeviation; + Color color; + if (!ArgumentCoder<IntPoint>::decode(decoder, location)) + return false; + if (!decoder.decode(stdDeviation)) + return false; + if (!ArgumentCoder<Color>::decode(decoder, color)) + return false; + filter = DropShadowFilterOperation::create(location, stdDeviation, color); + break; + } + case FilterOperation::REFERENCE: + case FilterOperation::PASSTHROUGH: + case FilterOperation::DEFAULT: + case FilterOperation::NONE: + break; + } + + if (filter) + operations.append(filter); + } + + return true; +} + +void ArgumentCoder<TransformOperations>::encode(Encoder& encoder, const TransformOperations& transformOperations) +{ + encoder << static_cast<uint32_t>(transformOperations.size()); + for (const auto& operation : transformOperations.operations()) { + encoder.encodeEnum(operation->type()); + + switch (operation->type()) { + case TransformOperation::SCALE_X: + case TransformOperation::SCALE_Y: + case TransformOperation::SCALE: + case TransformOperation::SCALE_Z: + case TransformOperation::SCALE_3D: { + const auto& scaleOperation = downcast<ScaleTransformOperation>(*operation); + encoder << scaleOperation.x(); + encoder << scaleOperation.y(); + encoder << scaleOperation.z(); + break; + } + case TransformOperation::TRANSLATE_X: + case TransformOperation::TRANSLATE_Y: + case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_Z: + case TransformOperation::TRANSLATE_3D: { + const auto& translateOperation = downcast<TranslateTransformOperation>(*operation); + ArgumentCoder<Length>::encode(encoder, translateOperation.x()); + ArgumentCoder<Length>::encode(encoder, translateOperation.y()); + ArgumentCoder<Length>::encode(encoder, translateOperation.z()); + break; + } + case TransformOperation::ROTATE: + case TransformOperation::ROTATE_X: + case TransformOperation::ROTATE_Y: + case TransformOperation::ROTATE_3D: { + const auto& rotateOperation = downcast<RotateTransformOperation>(*operation); + encoder << rotateOperation.x(); + encoder << rotateOperation.y(); + encoder << rotateOperation.z(); + encoder << rotateOperation.angle(); + break; + } + case TransformOperation::SKEW_X: + case TransformOperation::SKEW_Y: + case TransformOperation::SKEW: { + const auto& skewOperation = downcast<SkewTransformOperation>(*operation); + encoder << skewOperation.angleX(); + encoder << skewOperation.angleY(); + break; + } + case TransformOperation::MATRIX: + ArgumentCoder<TransformationMatrix>::encode(encoder, downcast<MatrixTransformOperation>(*operation).matrix()); + break; + case TransformOperation::MATRIX_3D: + ArgumentCoder<TransformationMatrix>::encode(encoder, downcast<Matrix3DTransformOperation>(*operation).matrix()); + break; + case TransformOperation::PERSPECTIVE: + ArgumentCoder<Length>::encode(encoder, downcast<PerspectiveTransformOperation>(*operation).perspective()); + break; + case TransformOperation::IDENTITY: + break; + case TransformOperation::NONE: + ASSERT_NOT_REACHED(); + break; + } + } +} + +bool ArgumentCoder<TransformOperations>::decode(Decoder& decoder, TransformOperations& transformOperations) +{ + uint32_t operationsSize; + if (!decoder.decode(operationsSize)) + return false; + + for (size_t i = 0; i < operationsSize; ++i) { + TransformOperation::OperationType operationType; + if (!decoder.decodeEnum(operationType)) + return false; + + switch (operationType) { + case TransformOperation::SCALE_X: + case TransformOperation::SCALE_Y: + case TransformOperation::SCALE: + case TransformOperation::SCALE_Z: + case TransformOperation::SCALE_3D: { + double x, y, z; + if (!decoder.decode(x)) + return false; + if (!decoder.decode(y)) + return false; + if (!decoder.decode(z)) + return false; + transformOperations.operations().append(ScaleTransformOperation::create(x, y, z, operationType)); + break; + } + case TransformOperation::TRANSLATE_X: + case TransformOperation::TRANSLATE_Y: + case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_Z: + case TransformOperation::TRANSLATE_3D: { + Length x, y, z; + if (!ArgumentCoder<Length>::decode(decoder, x)) + return false; + if (!ArgumentCoder<Length>::decode(decoder, y)) + return false; + if (!ArgumentCoder<Length>::decode(decoder, z)) + return false; + transformOperations.operations().append(TranslateTransformOperation::create(x, y, z, operationType)); + break; + } + case TransformOperation::ROTATE: + case TransformOperation::ROTATE_X: + case TransformOperation::ROTATE_Y: + case TransformOperation::ROTATE_3D: { + double x, y, z, angle; + if (!decoder.decode(x)) + return false; + if (!decoder.decode(y)) + return false; + if (!decoder.decode(z)) + return false; + if (!decoder.decode(angle)) + return false; + transformOperations.operations().append(RotateTransformOperation::create(x, y, z, angle, operationType)); + break; + } + case TransformOperation::SKEW_X: + case TransformOperation::SKEW_Y: + case TransformOperation::SKEW: { + double angleX, angleY; + if (!decoder.decode(angleX)) + return false; + if (!decoder.decode(angleY)) + return false; + transformOperations.operations().append(SkewTransformOperation::create(angleX, angleY, operationType)); + break; + } + case TransformOperation::MATRIX: { + TransformationMatrix matrix; + if (!ArgumentCoder<TransformationMatrix>::decode(decoder, matrix)) + return false; + transformOperations.operations().append(MatrixTransformOperation::create(matrix)); + break; + } + case TransformOperation::MATRIX_3D: { + TransformationMatrix matrix; + if (!ArgumentCoder<TransformationMatrix>::decode(decoder, matrix)) + return false; + transformOperations.operations().append(Matrix3DTransformOperation::create(matrix)); + break; + } + case TransformOperation::PERSPECTIVE: { + Length perspective; + if (!ArgumentCoder<Length>::decode(decoder, perspective)) + return false; + transformOperations.operations().append(PerspectiveTransformOperation::create(perspective)); + break; + } + case TransformOperation::IDENTITY: + transformOperations.operations().append(IdentityTransformOperation::create()); + break; + case TransformOperation::NONE: + ASSERT_NOT_REACHED(); + break; + } + } + return true; +} + +static void encodeTimingFunction(Encoder& encoder, const TimingFunction* timingFunction) +{ + if (!timingFunction) { + encoder.encodeEnum(TimingFunction::TimingFunctionType(-1)); + return; + } + + TimingFunction::TimingFunctionType type = timingFunction ? timingFunction->type() : TimingFunction::LinearFunction; + encoder.encodeEnum(type); + switch (type) { + case TimingFunction::LinearFunction: + break; + case TimingFunction::CubicBezierFunction: { + const CubicBezierTimingFunction* cubic = static_cast<const CubicBezierTimingFunction*>(timingFunction); + CubicBezierTimingFunction::TimingFunctionPreset bezierPreset = cubic->timingFunctionPreset(); + encoder.encodeEnum(bezierPreset); + if (bezierPreset == CubicBezierTimingFunction::Custom) { + encoder << cubic->x1(); + encoder << cubic->y1(); + encoder << cubic->x2(); + encoder << cubic->y2(); + } + break; + } + case TimingFunction::StepsFunction: { + const StepsTimingFunction* steps = static_cast<const StepsTimingFunction*>(timingFunction); + encoder << static_cast<uint32_t>(steps->numberOfSteps()); + encoder << steps->stepAtStart(); + break; + } + case TimingFunction::SpringFunction: { + const SpringTimingFunction* spring = static_cast<const SpringTimingFunction*>(timingFunction); + encoder << spring->mass(); + encoder << spring->stiffness(); + encoder << spring->damping(); + encoder << spring->initialVelocity(); + break; + } + } +} + +bool decodeTimingFunction(Decoder& decoder, RefPtr<TimingFunction>& timingFunction) +{ + TimingFunction::TimingFunctionType type; + if (!decoder.decodeEnum(type)) + return false; + + if (type == TimingFunction::TimingFunctionType(-1)) + return true; + + switch (type) { + case TimingFunction::LinearFunction: + timingFunction = LinearTimingFunction::create(); + return true; + case TimingFunction::CubicBezierFunction: { + double x1, y1, x2, y2; + CubicBezierTimingFunction::TimingFunctionPreset bezierPreset; + if (!decoder.decodeEnum(bezierPreset)) + return false; + if (bezierPreset != CubicBezierTimingFunction::Custom) { + timingFunction = CubicBezierTimingFunction::create(bezierPreset); + return true; + } + if (!decoder.decode(x1)) + return false; + if (!decoder.decode(y1)) + return false; + if (!decoder.decode(x2)) + return false; + if (!decoder.decode(y2)) + return false; + + timingFunction = CubicBezierTimingFunction::create(x1, y1, x2, y2); + return true; + } + case TimingFunction::StepsFunction: { + uint32_t numberOfSteps; + bool stepAtStart; + if (!decoder.decode(numberOfSteps)) + return false; + if (!decoder.decode(stepAtStart)) + return false; + + timingFunction = StepsTimingFunction::create(numberOfSteps, stepAtStart); + return true; + } + case TimingFunction::SpringFunction: { + double mass; + if (!decoder.decode(mass)) + return false; + double stiffness; + if (!decoder.decode(stiffness)) + return false; + double damping; + if (!decoder.decode(damping)) + return false; + double initialVelocity; + if (!decoder.decode(initialVelocity)) + return false; + + timingFunction = SpringTimingFunction::create(mass, stiffness, damping, initialVelocity); + return true; + } + } + + return false; +} + +void ArgumentCoder<TextureMapperAnimation>::encode(Encoder& encoder, const TextureMapperAnimation& animation) +{ + encoder << animation.name(); + encoder << animation.boxSize(); + encoder.encodeEnum(animation.state()); + encoder << animation.startTime(); + encoder << animation.pauseTime(); + encoder << animation.listsMatch(); + + RefPtr<Animation> animationObject = animation.animation(); + encoder.encodeEnum(animationObject->direction()); + encoder << static_cast<uint32_t>(animationObject->fillMode()); + encoder << animationObject->duration(); + encoder << animationObject->iterationCount(); + encodeTimingFunction(encoder, animationObject->timingFunction()); + + const KeyframeValueList& keyframes = animation.keyframes(); + encoder.encodeEnum(keyframes.property()); + encoder << static_cast<uint32_t>(keyframes.size()); + for (size_t i = 0; i < keyframes.size(); ++i) { + const AnimationValue& value = keyframes.at(i); + encoder << value.keyTime(); + encodeTimingFunction(encoder, value.timingFunction()); + switch (keyframes.property()) { + case AnimatedPropertyOpacity: + encoder << static_cast<const FloatAnimationValue&>(value).value(); + break; + case AnimatedPropertyTransform: + encoder << static_cast<const TransformAnimationValue&>(value).value(); + break; + case AnimatedPropertyFilter: + encoder << static_cast<const FilterAnimationValue&>(value).value(); + break; + default: + break; + } + } +} + +bool ArgumentCoder<TextureMapperAnimation>::decode(Decoder& decoder, TextureMapperAnimation& animation) +{ + String name; + FloatSize boxSize; + TextureMapperAnimation::AnimationState state; + double startTime; + double pauseTime; + bool listsMatch; + + Animation::AnimationDirection direction; + unsigned fillMode; + double duration; + double iterationCount; + RefPtr<TimingFunction> timingFunction; + RefPtr<Animation> animationObject; + + if (!decoder.decode(name)) + return false; + if (!decoder.decode(boxSize)) + return false; + if (!decoder.decodeEnum(state)) + return false; + if (!decoder.decode(startTime)) + return false; + if (!decoder.decode(pauseTime)) + return false; + if (!decoder.decode(listsMatch)) + return false; + if (!decoder.decodeEnum(direction)) + return false; + if (!decoder.decode(fillMode)) + return false; + if (!decoder.decode(duration)) + return false; + if (!decoder.decode(iterationCount)) + return false; + if (!decodeTimingFunction(decoder, timingFunction)) + return false; + + animationObject = Animation::create(); + animationObject->setDirection(direction); + animationObject->setFillMode(fillMode); + animationObject->setDuration(duration); + animationObject->setIterationCount(iterationCount); + if (timingFunction) + animationObject->setTimingFunction(WTFMove(timingFunction)); + + AnimatedPropertyID property; + if (!decoder.decodeEnum(property)) + return false; + KeyframeValueList keyframes(property); + unsigned keyframesSize; + if (!decoder.decode(keyframesSize)) + return false; + for (unsigned i = 0; i < keyframesSize; ++i) { + double keyTime; + RefPtr<TimingFunction> timingFunction; + if (!decoder.decode(keyTime)) + return false; + if (!decodeTimingFunction(decoder, timingFunction)) + return false; + + switch (property) { + case AnimatedPropertyOpacity: { + float value; + if (!decoder.decode(value)) + return false; + keyframes.insert(std::make_unique<FloatAnimationValue>(keyTime, value, timingFunction.get())); + break; + } + case AnimatedPropertyTransform: { + TransformOperations transform; + if (!decoder.decode(transform)) + return false; + keyframes.insert(std::make_unique<TransformAnimationValue>(keyTime, transform, timingFunction.get())); + break; + } + case AnimatedPropertyFilter: { + FilterOperations filter; + if (!decoder.decode(filter)) + return false; + keyframes.insert(std::make_unique<FilterAnimationValue>(keyTime, filter, timingFunction.get())); + break; + } + default: + break; + } + } + + animation = TextureMapperAnimation(name, keyframes, boxSize, *animationObject, listsMatch, startTime, pauseTime, state); + return true; +} + +void ArgumentCoder<TextureMapperAnimations>::encode(Encoder& encoder, const TextureMapperAnimations& animations) +{ + encoder << animations.animations(); +} + +bool ArgumentCoder<TextureMapperAnimations>::decode(Decoder& decoder, TextureMapperAnimations& animations) +{ + return decoder.decode(animations.animations()); +} + +bool ArgumentCoder<WebCore::GraphicsSurfaceToken>::decode(Decoder& decoder, WebCore::GraphicsSurfaceToken& token) +{ +#if OS(DARWIN) + Attachment frontAttachment, backAttachment; + if (!decoder.decode(frontAttachment)) + return false; + if (!decoder.decode(backAttachment)) + return false; + + token = GraphicsSurfaceToken(frontAttachment.port(), backAttachment.port()); +#elif OS(LINUX) + if (!decoder.decode(token.frontBufferHandle)) + return false; +#endif + return true; +} +#endif + +void ArgumentCoder<SurfaceUpdateInfo>::encode(Encoder& encoder, const SurfaceUpdateInfo& surfaceUpdateInfo) +{ + SimpleArgumentCoder<SurfaceUpdateInfo>::encode(encoder, surfaceUpdateInfo); +} + +bool ArgumentCoder<SurfaceUpdateInfo>::decode(Decoder& decoder, SurfaceUpdateInfo& surfaceUpdateInfo) +{ + return SimpleArgumentCoder<SurfaceUpdateInfo>::decode(decoder, surfaceUpdateInfo); +} + +void ArgumentCoder<CoordinatedGraphicsLayerState>::encode(Encoder& encoder, const CoordinatedGraphicsLayerState& state) +{ + encoder << state.changeMask; + + if (state.flagsChanged) + encoder << state.flags; + + if (state.positionChanged) + encoder << state.pos; + + if (state.anchorPointChanged) + encoder << state.anchorPoint; + + if (state.sizeChanged) + encoder << state.size; + + if (state.transformChanged) + encoder << state.transform; + + if (state.childrenTransformChanged) + encoder << state.childrenTransform; + + if (state.contentsRectChanged) + encoder << state.contentsRect; + + if (state.contentsTilingChanged) { + encoder << state.contentsTileSize; + encoder << state.contentsTilePhase; + } + + if (state.opacityChanged) + encoder << state.opacity; + + if (state.solidColorChanged) + encoder << state.solidColor; + + if (state.debugBorderColorChanged) + encoder << state.debugBorderColor; + + if (state.debugBorderWidthChanged) + encoder << state.debugBorderWidth; + + if (state.filtersChanged) + encoder << state.filters; + + if (state.animationsChanged) + encoder << state.animations; + + if (state.childrenChanged) + encoder << state.children; + + encoder << state.tilesToCreate; + encoder << state.tilesToRemove; + + if (state.replicaChanged) + encoder << state.replica; + + if (state.maskChanged) + encoder << state.mask; + + if (state.imageChanged) + encoder << state.imageID; + + if (state.repaintCountChanged) + encoder << state.repaintCount; + + encoder << state.tilesToUpdate; + + if (state.committedScrollOffsetChanged) + encoder << state.committedScrollOffset; +} + +bool ArgumentCoder<CoordinatedGraphicsLayerState>::decode(Decoder& decoder, CoordinatedGraphicsLayerState& state) +{ + if (!decoder.decode(state.changeMask)) + return false; + + if (state.flagsChanged && !decoder.decode(state.flags)) + return false; + + if (state.positionChanged && !decoder.decode(state.pos)) + return false; + + if (state.anchorPointChanged && !decoder.decode(state.anchorPoint)) + return false; + + if (state.sizeChanged && !decoder.decode(state.size)) + return false; + + if (state.transformChanged && !decoder.decode(state.transform)) + return false; + + if (state.childrenTransformChanged && !decoder.decode(state.childrenTransform)) + return false; + + if (state.contentsRectChanged && !decoder.decode(state.contentsRect)) + return false; + + if (state.contentsTilingChanged) { + if (!decoder.decode(state.contentsTileSize)) + return false; + if (!decoder.decode(state.contentsTilePhase)) + return false; + } + + if (state.opacityChanged && !decoder.decode(state.opacity)) + return false; + + if (state.solidColorChanged && !decoder.decode(state.solidColor)) + return false; + + if (state.debugBorderColorChanged && !decoder.decode(state.debugBorderColor)) + return false; + + if (state.debugBorderWidthChanged && !decoder.decode(state.debugBorderWidth)) + return false; + + if (state.filtersChanged && !decoder.decode(state.filters)) + return false; + + if (state.animationsChanged && !decoder.decode(state.animations)) + return false; + + if (state.childrenChanged && !decoder.decode(state.children)) + return false; + + if (!decoder.decode(state.tilesToCreate)) + return false; + + if (!decoder.decode(state.tilesToRemove)) + return false; + + if (state.replicaChanged && !decoder.decode(state.replica)) + return false; + + if (state.maskChanged && !decoder.decode(state.mask)) + return false; + + if (state.imageChanged && !decoder.decode(state.imageID)) + return false; + + if (state.repaintCountChanged && !decoder.decode(state.repaintCount)) + return false; + + if (!decoder.decode(state.tilesToUpdate)) + return false; + + if (state.committedScrollOffsetChanged && !decoder.decode(state.committedScrollOffset)) + return false; + + return true; +} + +void ArgumentCoder<TileUpdateInfo>::encode(Encoder& encoder, const TileUpdateInfo& updateInfo) +{ + SimpleArgumentCoder<TileUpdateInfo>::encode(encoder, updateInfo); +} + +bool ArgumentCoder<TileUpdateInfo>::decode(Decoder& decoder, TileUpdateInfo& updateInfo) +{ + return SimpleArgumentCoder<TileUpdateInfo>::decode(decoder, updateInfo); +} + +void ArgumentCoder<TileCreationInfo>::encode(Encoder& encoder, const TileCreationInfo& updateInfo) +{ + SimpleArgumentCoder<TileCreationInfo>::encode(encoder, updateInfo); +} + +bool ArgumentCoder<TileCreationInfo>::decode(Decoder& decoder, TileCreationInfo& updateInfo) +{ + return SimpleArgumentCoder<TileCreationInfo>::decode(decoder, updateInfo); +} + +static void encodeCoordinatedSurface(Encoder& encoder, const RefPtr<CoordinatedSurface>& surface) +{ + bool isValidSurface = false; + if (!surface) { + encoder << isValidSurface; + return; + } + + WebCoordinatedSurface* webCoordinatedSurface = static_cast<WebCoordinatedSurface*>(surface.get()); + WebCoordinatedSurface::Handle handle; + if (webCoordinatedSurface->createHandle(handle)) + isValidSurface = true; + + encoder << isValidSurface; + + if (isValidSurface) + encoder << handle; +} + +static bool decodeCoordinatedSurface(Decoder& decoder, RefPtr<CoordinatedSurface>& surface) +{ + bool isValidSurface; + if (!decoder.decode(isValidSurface)) + return false; + + if (!isValidSurface) + return true; + + WebCoordinatedSurface::Handle handle; + if (!decoder.decode(handle)) + return false; + + surface = WebCoordinatedSurface::create(handle); + return true; +} + +void ArgumentCoder<CoordinatedGraphicsState>::encode(Encoder& encoder, const CoordinatedGraphicsState& state) +{ + encoder << state.rootCompositingLayer; + encoder << state.scrollPosition; + encoder << state.contentsSize; + encoder << state.coveredRect; + + encoder << state.layersToCreate; + encoder << state.layersToUpdate; + encoder << state.layersToRemove; + + encoder << state.imagesToCreate; + encoder << state.imagesToRemove; + + // We need to encode WebCoordinatedSurface::Handle right after it's creation. + // That's why we cannot use simple std::pair encoder. + encoder << static_cast<uint64_t>(state.imagesToUpdate.size()); + for (size_t i = 0; i < state.imagesToUpdate.size(); ++i) { + encoder << state.imagesToUpdate[i].first; + encodeCoordinatedSurface(encoder, state.imagesToUpdate[i].second); + } + encoder << state.imagesToClear; + + encoder << static_cast<uint64_t>(state.updateAtlasesToCreate.size()); + for (size_t i = 0; i < state.updateAtlasesToCreate.size(); ++i) { + encoder << state.updateAtlasesToCreate[i].first; + encodeCoordinatedSurface(encoder, state.updateAtlasesToCreate[i].second); + } + encoder << state.updateAtlasesToRemove; +} + +bool ArgumentCoder<CoordinatedGraphicsState>::decode(Decoder& decoder, CoordinatedGraphicsState& state) +{ + if (!decoder.decode(state.rootCompositingLayer)) + return false; + + if (!decoder.decode(state.scrollPosition)) + return false; + + if (!decoder.decode(state.contentsSize)) + return false; + + if (!decoder.decode(state.coveredRect)) + return false; + + if (!decoder.decode(state.layersToCreate)) + return false; + + if (!decoder.decode(state.layersToUpdate)) + return false; + + if (!decoder.decode(state.layersToRemove)) + return false; + + if (!decoder.decode(state.imagesToCreate)) + return false; + + if (!decoder.decode(state.imagesToRemove)) + return false; + + uint64_t sizeOfImagesToUpdate; + if (!decoder.decode(sizeOfImagesToUpdate)) + return false; + + for (uint64_t i = 0; i < sizeOfImagesToUpdate; ++i) { + CoordinatedImageBackingID imageID; + if (!decoder.decode(imageID)) + return false; + + RefPtr<CoordinatedSurface> surface; + if (!decodeCoordinatedSurface(decoder, surface)) + return false; + + state.imagesToUpdate.append(std::make_pair(imageID, surface.release())); + } + + if (!decoder.decode(state.imagesToClear)) + return false; + + uint64_t sizeOfUpdateAtlasesToCreate; + if (!decoder.decode(sizeOfUpdateAtlasesToCreate)) + return false; + + for (uint64_t i = 0; i < sizeOfUpdateAtlasesToCreate; ++i) { + uint32_t atlasID; + if (!decoder.decode(atlasID)) + return false; + + RefPtr<CoordinatedSurface> surface; + if (!decodeCoordinatedSurface(decoder, surface)) + return false; + + state.updateAtlasesToCreate.append(std::make_pair(atlasID, surface.release())); + } + + if (!decoder.decode(state.updateAtlasesToRemove)) + return false; + + return true; +} + +} // namespace IPC + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsArgumentCoders.h b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsArgumentCoders.h new file mode 100644 index 000000000..dd0c10b59 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsArgumentCoders.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2012 Company 100, 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. + */ + +#ifndef CoordinatedGraphicsArgumentCoders_h +#define CoordinatedGraphicsArgumentCoders_h + +#if USE(COORDINATED_GRAPHICS) +#include "ArgumentCoders.h" + +namespace WebCore { +struct CoordinatedGraphicsLayerState; +struct CoordinatedGraphicsState; +class FloatPoint3D; +class TextureMapperAnimation; +class TextureMapperAnimations; +class SurfaceUpdateInfo; +struct TileCreationInfo; +struct TileUpdateInfo; +class TransformationMatrix; +class TransformOperations; +struct Length; + +class FilterOperations; +} + +namespace IPC { + +template<> struct ArgumentCoder<WebCore::FilterOperations> { + static void encode(Encoder&, const WebCore::FilterOperations&); + static bool decode(Decoder&, WebCore::FilterOperations&); +}; + +template<> struct ArgumentCoder<WebCore::TransformOperations> { + static void encode(Encoder&, const WebCore::TransformOperations&); + static bool decode(Decoder&, WebCore::TransformOperations&); +}; + +template<> struct ArgumentCoder<WebCore::TextureMapperAnimations> { + static void encode(Encoder&, const WebCore::TextureMapperAnimations&); + static bool decode(Decoder&, WebCore::TextureMapperAnimations&); +}; + +template<> struct ArgumentCoder<WebCore::TextureMapperAnimation> { + static void encode(Encoder&, const WebCore::TextureMapperAnimation&); + static bool decode(Decoder&, WebCore::TextureMapperAnimation&); +}; + +template<> struct ArgumentCoder<WebCore::SurfaceUpdateInfo> { + static void encode(Encoder&, const WebCore::SurfaceUpdateInfo&); + static bool decode(Decoder&, WebCore::SurfaceUpdateInfo&); +}; + +template<> struct ArgumentCoder<WebCore::CoordinatedGraphicsLayerState> { + static void encode(Encoder&, const WebCore::CoordinatedGraphicsLayerState&); + static bool decode(Decoder&, WebCore::CoordinatedGraphicsLayerState&); +}; + +template<> struct ArgumentCoder<WebCore::TileUpdateInfo> { + static void encode(Encoder&, const WebCore::TileUpdateInfo&); + static bool decode(Decoder&, WebCore::TileUpdateInfo&); +}; + +template<> struct ArgumentCoder<WebCore::TileCreationInfo> { + static void encode(Encoder&, const WebCore::TileCreationInfo&); + static bool decode(Decoder&, WebCore::TileCreationInfo&); +}; + +template<> struct ArgumentCoder<WebCore::CoordinatedGraphicsState> { + static void encode(Encoder&, const WebCore::CoordinatedGraphicsState&); + static bool decode(Decoder&, WebCore::CoordinatedGraphicsState&); +}; + +} // namespace IPC + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedGraphicsArgumentCoders_h diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp new file mode 100644 index 000000000..b94faea2c --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp @@ -0,0 +1,682 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedGraphicsScene.h" + +#include "CoordinatedBackingStore.h" +#include <WebCore/TextureMapper.h> +#include <WebCore/TextureMapperBackingStore.h> +#include <WebCore/TextureMapperGL.h> +#include <WebCore/TextureMapperLayer.h> +#include <wtf/Atomics.h> + +using namespace WebCore; + +namespace WebKit { + +void CoordinatedGraphicsScene::dispatchOnMainThread(Function<void()>&& function) +{ + if (isMainThread()) { + function(); + return; + } + + RunLoop::main().dispatch([protectedThis = makeRef(*this), function = WTFMove(function)] { + function(); + }); +} + +void CoordinatedGraphicsScene::dispatchOnClientRunLoop(Function<void()>&& function) +{ + if (&m_clientRunLoop == &RunLoop::current()) { + function(); + return; + } + + m_clientRunLoop.dispatch([protectedThis = makeRef(*this), function = WTFMove(function)] { + function(); + }); +} + +static bool layerShouldHaveBackingStore(TextureMapperLayer* layer) +{ + return layer->drawsContent() && layer->contentsAreVisible() && !layer->size().isEmpty(); +} + +CoordinatedGraphicsScene::CoordinatedGraphicsScene(CoordinatedGraphicsSceneClient* client) + : m_client(client) + , m_isActive(false) + , m_rootLayerID(InvalidCoordinatedLayerID) + , m_viewBackgroundColor(Color::white) + , m_clientRunLoop(RunLoop::current()) +{ +} + +CoordinatedGraphicsScene::~CoordinatedGraphicsScene() +{ +} + +void CoordinatedGraphicsScene::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity, const FloatRect& clipRect, const Color& backgroundColor, bool drawsBackground, const FloatPoint& contentPosition, TextureMapper::PaintFlags PaintFlags) +{ + if (!m_textureMapper) { + m_textureMapper = TextureMapper::create(); + static_cast<TextureMapperGL*>(m_textureMapper.get())->setEnableEdgeDistanceAntialiasing(true); + } + + syncRemoteContent(); + + adjustPositionForFixedLayers(contentPosition); + TextureMapperLayer* currentRootLayer = rootLayer(); + if (!currentRootLayer) + return; + +#if USE(COORDINATED_GRAPHICS_THREADED) + for (auto& proxy : m_platformLayerProxies.values()) + proxy->swapBuffer(); +#endif + + currentRootLayer->setTextureMapper(m_textureMapper.get()); + currentRootLayer->applyAnimationsRecursively(); + m_textureMapper->beginPainting(PaintFlags); + m_textureMapper->beginClip(TransformationMatrix(), clipRect); + + if (drawsBackground) { + RGBA32 rgba = makeRGBA32FromFloats(backgroundColor.red(), + backgroundColor.green(), backgroundColor.blue(), + backgroundColor.alpha() * opacity); + m_textureMapper->drawSolidColor(clipRect, TransformationMatrix(), Color(rgba)); + } else { + GraphicsContext3D* context = static_cast<TextureMapperGL*>(m_textureMapper.get())->graphicsContext3D(); + context->clearColor(m_viewBackgroundColor.red() / 255.0f, m_viewBackgroundColor.green() / 255.0f, m_viewBackgroundColor.blue() / 255.0f, m_viewBackgroundColor.alpha() / 255.0f); + context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); + } + + if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != matrix) { + currentRootLayer->setOpacity(opacity); + currentRootLayer->setTransform(matrix); + } + + currentRootLayer->paint(); + m_fpsCounter.updateFPSAndDisplay(*m_textureMapper, clipRect.location(), matrix); + m_textureMapper->endClip(); + m_textureMapper->endPainting(); + + if (currentRootLayer->descendantsOrSelfHaveRunningAnimations()) + updateViewport(); +} + +void CoordinatedGraphicsScene::updateViewport() +{ + if (!m_client) + return; + dispatchOnClientRunLoop([this] { + if (m_client) + m_client->updateViewport(); + }); +} + +void CoordinatedGraphicsScene::adjustPositionForFixedLayers(const FloatPoint& contentPosition) +{ + if (m_fixedLayers.isEmpty()) + return; + + // Fixed layer positions are updated by the web process when we update the visible contents rect / scroll position. + // If we want those layers to follow accurately the viewport when we move between the web process updates, we have to offset + // them by the delta between the current position and the position of the viewport used for the last layout. + FloatSize delta = contentPosition - m_renderedContentsScrollPosition; + + for (auto& fixedLayer : m_fixedLayers.values()) + fixedLayer->setScrollPositionDeltaIfNeeded(delta); +} + +void CoordinatedGraphicsScene::syncPlatformLayerIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ +#if USE(COORDINATED_GRAPHICS_THREADED) + if (!state.platformLayerChanged) + return; + + if (state.platformLayerProxy) { + m_platformLayerProxies.set(layer, state.platformLayerProxy); + state.platformLayerProxy->activateOnCompositingThread(this, layer); + } else + m_platformLayerProxies.remove(layer); +#else + UNUSED_PARAM(layer); + UNUSED_PARAM(state); +#endif +} + +#if USE(COORDINATED_GRAPHICS_THREADED) +void CoordinatedGraphicsScene::onNewBufferAvailable() +{ + updateViewport(); +} +#endif + +void CoordinatedGraphicsScene::setLayerRepaintCountIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!layer->isShowingRepaintCounter() || !state.repaintCountChanged) + return; + + layer->setRepaintCount(state.repaintCount); +} + +void CoordinatedGraphicsScene::setLayerChildrenIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!state.childrenChanged) + return; + + Vector<TextureMapperLayer*> children; + children.reserveCapacity(state.children.size()); + for (auto& child : state.children) + children.append(layerByID(child)); + + layer->setChildren(children); +} + +void CoordinatedGraphicsScene::setLayerFiltersIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!state.filtersChanged) + return; + + layer->setFilters(state.filters); +} + +void CoordinatedGraphicsScene::setLayerState(CoordinatedLayerID id, const CoordinatedGraphicsLayerState& layerState) +{ + ASSERT(m_rootLayerID != InvalidCoordinatedLayerID); + TextureMapperLayer* layer = layerByID(id); + + if (layerState.positionChanged) + layer->setPosition(layerState.pos); + + if (layerState.anchorPointChanged) + layer->setAnchorPoint(layerState.anchorPoint); + + if (layerState.sizeChanged) + layer->setSize(layerState.size); + + if (layerState.transformChanged) + layer->setTransform(layerState.transform); + + if (layerState.childrenTransformChanged) + layer->setChildrenTransform(layerState.childrenTransform); + + if (layerState.contentsRectChanged) + layer->setContentsRect(layerState.contentsRect); + + if (layerState.contentsTilingChanged) { + layer->setContentsTilePhase(layerState.contentsTilePhase); + layer->setContentsTileSize(layerState.contentsTileSize); + } + + if (layerState.opacityChanged) + layer->setOpacity(layerState.opacity); + + if (layerState.solidColorChanged) + layer->setSolidColor(layerState.solidColor); + + if (layerState.debugBorderColorChanged || layerState.debugBorderWidthChanged) + layer->setDebugVisuals(layerState.showDebugBorders, layerState.debugBorderColor, layerState.debugBorderWidth, layerState.showRepaintCounter); + + if (layerState.replicaChanged) + layer->setReplicaLayer(getLayerByIDIfExists(layerState.replica)); + + if (layerState.maskChanged) + layer->setMaskLayer(getLayerByIDIfExists(layerState.mask)); + + if (layerState.imageChanged) + assignImageBackingToLayer(layer, layerState.imageID); + + if (layerState.flagsChanged) { + layer->setContentsOpaque(layerState.contentsOpaque); + layer->setDrawsContent(layerState.drawsContent); + layer->setContentsVisible(layerState.contentsVisible); + layer->setBackfaceVisibility(layerState.backfaceVisible); + + // Never clip the root layer. + layer->setMasksToBounds(id == m_rootLayerID ? false : layerState.masksToBounds); + layer->setPreserves3D(layerState.preserves3D); + + bool fixedToViewportChanged = layer->fixedToViewport() != layerState.fixedToViewport; + layer->setFixedToViewport(layerState.fixedToViewport); + if (fixedToViewportChanged) { + if (layerState.fixedToViewport) + m_fixedLayers.add(id, layer); + else + m_fixedLayers.remove(id); + } + + layer->setIsScrollable(layerState.isScrollable); + } + + if (layerState.committedScrollOffsetChanged) + layer->didCommitScrollOffset(layerState.committedScrollOffset); + + prepareContentBackingStore(layer); + + // Apply Operations. + setLayerChildrenIfNeeded(layer, layerState); + createTilesIfNeeded(layer, layerState); + removeTilesIfNeeded(layer, layerState); + updateTilesIfNeeded(layer, layerState); + setLayerFiltersIfNeeded(layer, layerState); + setLayerAnimationsIfNeeded(layer, layerState); + syncPlatformLayerIfNeeded(layer, layerState); + setLayerRepaintCountIfNeeded(layer, layerState); +} + +TextureMapperLayer* CoordinatedGraphicsScene::getLayerByIDIfExists(CoordinatedLayerID id) +{ + return (id != InvalidCoordinatedLayerID) ? layerByID(id) : 0; +} + +void CoordinatedGraphicsScene::createLayers(const Vector<CoordinatedLayerID>& layerIDs) +{ + for (auto& layerID : layerIDs) + createLayer(layerID); +} + +void CoordinatedGraphicsScene::createLayer(CoordinatedLayerID id) +{ + std::unique_ptr<TextureMapperLayer> newLayer = std::make_unique<TextureMapperLayer>(); + newLayer->setID(id); + newLayer->setScrollClient(this); + m_layers.add(id, WTFMove(newLayer)); +} + +void CoordinatedGraphicsScene::deleteLayers(const Vector<CoordinatedLayerID>& layerIDs) +{ + for (auto& layerID : layerIDs) + deleteLayer(layerID); +} + +void CoordinatedGraphicsScene::deleteLayer(CoordinatedLayerID layerID) +{ + std::unique_ptr<TextureMapperLayer> layer = m_layers.take(layerID); + ASSERT(layer); + + m_backingStores.remove(layer.get()); + m_fixedLayers.remove(layerID); +#if USE(COORDINATED_GRAPHICS_THREADED) + if (auto platformLayerProxy = m_platformLayerProxies.take(layer.get())) + platformLayerProxy->invalidate(); +#endif +} + +void CoordinatedGraphicsScene::setRootLayerID(CoordinatedLayerID layerID) +{ + ASSERT(layerID != InvalidCoordinatedLayerID); + ASSERT(m_rootLayerID == InvalidCoordinatedLayerID); + + m_rootLayerID = layerID; + + TextureMapperLayer* layer = layerByID(layerID); + ASSERT(m_rootLayer->children().isEmpty()); + m_rootLayer->addChild(layer); +} + +void CoordinatedGraphicsScene::prepareContentBackingStore(TextureMapperLayer* layer) +{ + if (!layerShouldHaveBackingStore(layer)) { + removeBackingStoreIfNeeded(layer); + return; + } + + createBackingStoreIfNeeded(layer); + resetBackingStoreSizeToLayerSize(layer); +} + +void CoordinatedGraphicsScene::createBackingStoreIfNeeded(TextureMapperLayer* layer) +{ + if (m_backingStores.contains(layer)) + return; + + RefPtr<CoordinatedBackingStore> backingStore(CoordinatedBackingStore::create()); + m_backingStores.add(layer, backingStore); + layer->setBackingStore(backingStore); +} + +void CoordinatedGraphicsScene::removeBackingStoreIfNeeded(TextureMapperLayer* layer) +{ + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.take(layer); + if (!backingStore) + return; + + layer->setBackingStore(0); +} + +void CoordinatedGraphicsScene::resetBackingStoreSizeToLayerSize(TextureMapperLayer* layer) +{ + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + ASSERT(backingStore); + backingStore->setSize(layer->size()); + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::createTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (state.tilesToCreate.isEmpty()) + return; + + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + ASSERT(backingStore || !layerShouldHaveBackingStore(layer)); + if (!backingStore) + return; + + for (auto& tile : state.tilesToCreate) + backingStore->createTile(tile.tileID, tile.scale); +} + +void CoordinatedGraphicsScene::removeTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (state.tilesToRemove.isEmpty()) + return; + + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + if (!backingStore) + return; + + for (auto& tile : state.tilesToRemove) + backingStore->removeTile(tile); + + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::updateTilesIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (state.tilesToUpdate.isEmpty()) + return; + + RefPtr<CoordinatedBackingStore> backingStore = m_backingStores.get(layer); + ASSERT(backingStore || !layerShouldHaveBackingStore(layer)); + if (!backingStore) + return; + + for (auto& tile : state.tilesToUpdate) { + const SurfaceUpdateInfo& surfaceUpdateInfo = tile.updateInfo; + + SurfaceMap::iterator surfaceIt = m_surfaces.find(surfaceUpdateInfo.atlasID); + ASSERT(surfaceIt != m_surfaces.end()); + + backingStore->updateTile(tile.tileID, surfaceUpdateInfo.updateRect, tile.tileRect, surfaceIt->value, surfaceUpdateInfo.surfaceOffset); + m_backingStoresWithPendingBuffers.add(backingStore); + } +} + +void CoordinatedGraphicsScene::syncUpdateAtlases(const CoordinatedGraphicsState& state) +{ + for (auto& atlas : state.updateAtlasesToCreate) + createUpdateAtlas(atlas.first, atlas.second); + + for (auto& atlas : state.updateAtlasesToRemove) + removeUpdateAtlas(atlas); +} + +void CoordinatedGraphicsScene::createUpdateAtlas(uint32_t atlasID, PassRefPtr<CoordinatedSurface> surface) +{ + ASSERT(!m_surfaces.contains(atlasID)); + m_surfaces.add(atlasID, surface); +} + +void CoordinatedGraphicsScene::removeUpdateAtlas(uint32_t atlasID) +{ + ASSERT(m_surfaces.contains(atlasID)); + m_surfaces.remove(atlasID); +} + +void CoordinatedGraphicsScene::syncImageBackings(const CoordinatedGraphicsState& state) +{ + for (auto& image : state.imagesToRemove) + removeImageBacking(image); + + for (auto& image : state.imagesToCreate) + createImageBacking(image); + + for (auto& image : state.imagesToUpdate) + updateImageBacking(image.first, image.second); + + for (auto& image : state.imagesToClear) + clearImageBackingContents(image); +} + +void CoordinatedGraphicsScene::createImageBacking(CoordinatedImageBackingID imageID) +{ + ASSERT(!m_imageBackings.contains(imageID)); + RefPtr<CoordinatedBackingStore> backingStore(CoordinatedBackingStore::create()); + m_imageBackings.add(imageID, backingStore.release()); +} + +void CoordinatedGraphicsScene::updateImageBacking(CoordinatedImageBackingID imageID, PassRefPtr<CoordinatedSurface> surface) +{ + ASSERT(m_imageBackings.contains(imageID)); + ImageBackingMap::iterator it = m_imageBackings.find(imageID); + RefPtr<CoordinatedBackingStore> backingStore = it->value; + + // CoordinatedImageBacking is realized to CoordinatedBackingStore with only one tile in UI Process. + backingStore->createTile(1 /* id */, 1 /* scale */); + IntRect rect(IntPoint::zero(), surface->size()); + // See CoordinatedGraphicsLayer::shouldDirectlyCompositeImage() + ASSERT(2000 >= std::max(rect.width(), rect.height())); + backingStore->setSize(rect.size()); + backingStore->updateTile(1 /* id */, rect, rect, surface, rect.location()); + + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::clearImageBackingContents(CoordinatedImageBackingID imageID) +{ + ASSERT(m_imageBackings.contains(imageID)); + ImageBackingMap::iterator it = m_imageBackings.find(imageID); + RefPtr<CoordinatedBackingStore> backingStore = it->value; + backingStore->removeAllTiles(); + m_backingStoresWithPendingBuffers.add(backingStore); +} + +void CoordinatedGraphicsScene::removeImageBacking(CoordinatedImageBackingID imageID) +{ + ASSERT(m_imageBackings.contains(imageID)); + + // We don't want TextureMapperLayer refers a dangling pointer. + m_releasedImageBackings.append(m_imageBackings.take(imageID)); +} + +void CoordinatedGraphicsScene::assignImageBackingToLayer(TextureMapperLayer* layer, CoordinatedImageBackingID imageID) +{ + if (imageID == InvalidCoordinatedImageBackingID) { + layer->setContentsLayer(0); + return; + } + + ImageBackingMap::iterator it = m_imageBackings.find(imageID); + ASSERT(it != m_imageBackings.end()); + layer->setContentsLayer(it->value.get()); +} + +void CoordinatedGraphicsScene::removeReleasedImageBackingsIfNeeded() +{ + m_releasedImageBackings.clear(); +} + +void CoordinatedGraphicsScene::commitPendingBackingStoreOperations() +{ + for (auto& backingStore : m_backingStoresWithPendingBuffers) + backingStore->commitTileOperations(*m_textureMapper); + + m_backingStoresWithPendingBuffers.clear(); +} + +void CoordinatedGraphicsScene::commitSceneState(const CoordinatedGraphicsState& state) +{ + if (!m_client) + return; + + m_renderedContentsScrollPosition = state.scrollPosition; + + createLayers(state.layersToCreate); + deleteLayers(state.layersToRemove); + + if (state.rootCompositingLayer != m_rootLayerID) + setRootLayerID(state.rootCompositingLayer); + + syncImageBackings(state); + syncUpdateAtlases(state); + + for (auto& layer : state.layersToUpdate) + setLayerState(layer.first, layer.second); + + commitPendingBackingStoreOperations(); + removeReleasedImageBackingsIfNeeded(); + + // The pending tiles state is on its way for the screen, tell the web process to render the next one. + renderNextFrame(); +} + +void CoordinatedGraphicsScene::renderNextFrame() +{ + if (!m_client) + return; + dispatchOnMainThread([this] { + if (m_client) + m_client->renderNextFrame(); + }); +} + +void CoordinatedGraphicsScene::ensureRootLayer() +{ + if (m_rootLayer) + return; + + m_rootLayer = std::make_unique<TextureMapperLayer>(); + m_rootLayer->setMasksToBounds(false); + m_rootLayer->setDrawsContent(false); + m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0)); + + // The root layer should not have zero size, or it would be optimized out. + m_rootLayer->setSize(FloatSize(1.0, 1.0)); + + ASSERT(m_textureMapper); + m_rootLayer->setTextureMapper(m_textureMapper.get()); +} + +void CoordinatedGraphicsScene::syncRemoteContent() +{ + // We enqueue messages and execute them during paint, as they require an active GL context. + ensureRootLayer(); + + Vector<std::function<void()>> renderQueue; + bool calledOnMainThread = WTF::isMainThread(); + if (!calledOnMainThread) + m_renderQueueMutex.lock(); + renderQueue = WTFMove(m_renderQueue); + if (!calledOnMainThread) + m_renderQueueMutex.unlock(); + + for (auto& function : renderQueue) + function(); +} + +void CoordinatedGraphicsScene::purgeGLResources() +{ + ASSERT(!m_client); + + m_imageBackings.clear(); + m_releasedImageBackings.clear(); +#if USE(COORDINATED_GRAPHICS_THREADED) + for (auto& proxy : m_platformLayerProxies.values()) + proxy->invalidate(); + m_platformLayerProxies.clear(); +#endif + m_surfaces.clear(); + + m_rootLayer = nullptr; + m_rootLayerID = InvalidCoordinatedLayerID; + m_layers.clear(); + m_fixedLayers.clear(); + m_textureMapper = nullptr; + m_backingStores.clear(); + m_backingStoresWithPendingBuffers.clear(); +} + +void CoordinatedGraphicsScene::commitScrollOffset(uint32_t layerID, const IntSize& offset) +{ + if (!m_client) + return; + dispatchOnMainThread([this, layerID, offset] { + if (m_client) + m_client->commitScrollOffset(layerID, offset); + }); +} + +void CoordinatedGraphicsScene::setLayerAnimationsIfNeeded(TextureMapperLayer* layer, const CoordinatedGraphicsLayerState& state) +{ + if (!state.animationsChanged) + return; + + layer->setAnimations(state.animations); +} + +void CoordinatedGraphicsScene::detach() +{ + ASSERT(isMainThread()); + m_isActive = false; + m_client = nullptr; + LockHolder locker(m_renderQueueMutex); + m_renderQueue.clear(); +} + +void CoordinatedGraphicsScene::appendUpdate(std::function<void()>&& function) +{ + if (!m_isActive) + return; + + ASSERT(isMainThread()); + LockHolder locker(m_renderQueueMutex); + m_renderQueue.append(WTFMove(function)); +} + +void CoordinatedGraphicsScene::setActive(bool active) +{ + if (!m_client) + return; + + if (m_isActive == active) + return; + + // Have to clear render queue in both cases. + // If there are some updates in queue during activation then those updates are from previous instance of paint node + // and cannot be applied to the newly created instance. + m_renderQueue.clear(); + m_isActive = active; + if (m_isActive) + renderNextFrame(); +} + +TextureMapperLayer* CoordinatedGraphicsScene::findScrollableContentsLayerAt(const FloatPoint& point) +{ + return rootLayer() ? rootLayer()->findScrollableContentsLayerAt(point) : 0; +} + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.h b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.h new file mode 100644 index 000000000..128b7be76 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.h @@ -0,0 +1,194 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2013 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef CoordinatedGraphicsScene_h +#define CoordinatedGraphicsScene_h + +#if USE(COORDINATED_GRAPHICS) +#include <WebCore/CoordinatedGraphicsState.h> +#include <WebCore/CoordinatedSurface.h> +#include <WebCore/GraphicsContext.h> +#include <WebCore/GraphicsLayer.h> +#include <WebCore/IntRect.h> +#include <WebCore/IntSize.h> +#include <WebCore/TextureMapper.h> +#include <WebCore/TextureMapperBackingStore.h> +#include <WebCore/TextureMapperFPSCounter.h> +#include <WebCore/TextureMapperLayer.h> +#include <WebCore/Timer.h> +#include <wtf/Function.h> +#include <wtf/HashSet.h> +#include <wtf/Lock.h> +#include <wtf/RunLoop.h> +#include <wtf/ThreadingPrimitives.h> +#include <wtf/Vector.h> + +#if USE(COORDINATED_GRAPHICS_THREADED) +#include <WebCore/TextureMapperPlatformLayerProxy.h> +#endif + +namespace WebKit { + +class CoordinatedBackingStore; + +class CoordinatedGraphicsSceneClient { +public: + virtual ~CoordinatedGraphicsSceneClient() { } + virtual void renderNextFrame() = 0; + virtual void updateViewport() = 0; + virtual void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) = 0; +}; + +class CoordinatedGraphicsScene : public ThreadSafeRefCounted<CoordinatedGraphicsScene>, public WebCore::TextureMapperLayer::ScrollingClient +#if USE(COORDINATED_GRAPHICS_THREADED) + , public WebCore::TextureMapperPlatformLayerProxy::Compositor +#endif +{ +public: + explicit CoordinatedGraphicsScene(CoordinatedGraphicsSceneClient*); + virtual ~CoordinatedGraphicsScene(); + void paintToCurrentGLContext(const WebCore::TransformationMatrix&, float, const WebCore::FloatRect&, const WebCore::Color& backgroundColor, bool drawsBackground, const WebCore::FloatPoint&, WebCore::TextureMapper::PaintFlags = 0); + void detach(); + void appendUpdate(std::function<void()>&&); + + WebCore::TextureMapperLayer* findScrollableContentsLayerAt(const WebCore::FloatPoint&); + + void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) override; + + // The painting thread must lock the main thread to use below two methods, because two methods access members that the main thread manages. See m_client. + // Currently, QQuickWebPage::updatePaintNode() locks the main thread before calling both methods. + void purgeGLResources(); + + bool isActive() const { return m_isActive; } + void setActive(bool); + + void commitSceneState(const WebCore::CoordinatedGraphicsState&); + + void setViewBackgroundColor(const WebCore::Color& color) { m_viewBackgroundColor = color; } + WebCore::Color viewBackgroundColor() const { return m_viewBackgroundColor; } + +private: + void setRootLayerID(WebCore::CoordinatedLayerID); + void createLayers(const Vector<WebCore::CoordinatedLayerID>&); + void deleteLayers(const Vector<WebCore::CoordinatedLayerID>&); + void setLayerState(WebCore::CoordinatedLayerID, const WebCore::CoordinatedGraphicsLayerState&); + void setLayerChildrenIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + void updateTilesIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + void createTilesIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + void removeTilesIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + void setLayerFiltersIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + void setLayerAnimationsIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + void syncPlatformLayerIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + void setLayerRepaintCountIfNeeded(WebCore::TextureMapperLayer*, const WebCore::CoordinatedGraphicsLayerState&); + + void syncUpdateAtlases(const WebCore::CoordinatedGraphicsState&); + void createUpdateAtlas(uint32_t atlasID, PassRefPtr<WebCore::CoordinatedSurface>); + void removeUpdateAtlas(uint32_t atlasID); + + void syncImageBackings(const WebCore::CoordinatedGraphicsState&); + void createImageBacking(WebCore::CoordinatedImageBackingID); + void updateImageBacking(WebCore::CoordinatedImageBackingID, PassRefPtr<WebCore::CoordinatedSurface>); + void clearImageBackingContents(WebCore::CoordinatedImageBackingID); + void removeImageBacking(WebCore::CoordinatedImageBackingID); + + WebCore::TextureMapperLayer* layerByID(WebCore::CoordinatedLayerID id) + { + ASSERT(m_layers.contains(id)); + ASSERT(id != WebCore::InvalidCoordinatedLayerID); + return m_layers.get(id); + } + WebCore::TextureMapperLayer* getLayerByIDIfExists(WebCore::CoordinatedLayerID); + WebCore::TextureMapperLayer* rootLayer() { return m_rootLayer.get(); } + + void syncRemoteContent(); + void adjustPositionForFixedLayers(const WebCore::FloatPoint& contentPosition); + + void dispatchOnMainThread(Function<void()>&&); + void dispatchOnClientRunLoop(Function<void()>&&); + void updateViewport(); + void renderNextFrame(); + + void createLayer(WebCore::CoordinatedLayerID); + void deleteLayer(WebCore::CoordinatedLayerID); + + void assignImageBackingToLayer(WebCore::TextureMapperLayer*, WebCore::CoordinatedImageBackingID); + void removeReleasedImageBackingsIfNeeded(); + void ensureRootLayer(); + void commitPendingBackingStoreOperations(); + + void prepareContentBackingStore(WebCore::TextureMapperLayer*); + void createBackingStoreIfNeeded(WebCore::TextureMapperLayer*); + void removeBackingStoreIfNeeded(WebCore::TextureMapperLayer*); + void resetBackingStoreSizeToLayerSize(WebCore::TextureMapperLayer*); + +#if USE(COORDINATED_GRAPHICS_THREADED) + void onNewBufferAvailable() override; +#endif + + // Render queue can be accessed ony from main thread or updatePaintNode call stack! + Vector<std::function<void()>> m_renderQueue; + Lock m_renderQueueMutex; + + std::unique_ptr<WebCore::TextureMapper> m_textureMapper; + + typedef HashMap<WebCore::CoordinatedImageBackingID, RefPtr<CoordinatedBackingStore>> ImageBackingMap; + ImageBackingMap m_imageBackings; + Vector<RefPtr<CoordinatedBackingStore>> m_releasedImageBackings; + + typedef HashMap<WebCore::TextureMapperLayer*, RefPtr<CoordinatedBackingStore>> BackingStoreMap; + BackingStoreMap m_backingStores; + + HashSet<RefPtr<CoordinatedBackingStore>> m_backingStoresWithPendingBuffers; + +#if USE(COORDINATED_GRAPHICS_THREADED) + typedef HashMap<WebCore::TextureMapperLayer*, RefPtr<WebCore::TextureMapperPlatformLayerProxy>> PlatformLayerProxyMap; + PlatformLayerProxyMap m_platformLayerProxies; +#endif + + typedef HashMap<uint32_t /* atlasID */, RefPtr<WebCore::CoordinatedSurface>> SurfaceMap; + SurfaceMap m_surfaces; + + // Below two members are accessed by only the main thread. The painting thread must lock the main thread to access both members. + CoordinatedGraphicsSceneClient* m_client; + bool m_isActive; + + std::unique_ptr<WebCore::TextureMapperLayer> m_rootLayer; + + typedef HashMap<WebCore::CoordinatedLayerID, std::unique_ptr<WebCore::TextureMapperLayer>> LayerMap; + LayerMap m_layers; + typedef HashMap<WebCore::CoordinatedLayerID, WebCore::TextureMapperLayer*> LayerRawPtrMap; + LayerRawPtrMap m_fixedLayers; + WebCore::CoordinatedLayerID m_rootLayerID; + WebCore::FloatPoint m_scrollPosition; + WebCore::FloatPoint m_renderedContentsScrollPosition; + WebCore::Color m_viewBackgroundColor; + + WebCore::TextureMapperFPSCounter m_fpsCounter; + + RunLoop& m_clientRunLoop; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedGraphicsScene_h + + diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.cpp new file mode 100644 index 000000000..a5eaafea4 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2011, 2012 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * Copyright (C) 2014 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "SimpleViewportController.h" + +#if USE(COORDINATED_GRAPHICS_THREADED) + +using namespace WebCore; + +namespace WebKit { + +SimpleViewportController::SimpleViewportController(const IntSize& size) + : m_viewportSize(size) +{ + resetViewportToDefaultState(); +} + +void SimpleViewportController::didChangeViewportSize(const IntSize& newSize) +{ + if (newSize.isEmpty()) + return; + + m_viewportSize = newSize; + updateMinimumScaleToFit(); +} + +void SimpleViewportController::didChangeContentsSize(const IntSize& newSize) +{ + m_contentsSize = newSize; + + updateMinimumScaleToFit(); + + if (m_initiallyFitToViewport) { + // Restrict scale factors to m_minimumScaleToFit. + ASSERT(m_minimumScaleToFit > 0); + m_rawAttributes.initialScale = m_minimumScaleToFit; + restrictScaleFactorToInitialScaleIfNotUserScalable(m_rawAttributes); + } +} + +void SimpleViewportController::didChangeViewportAttributes(ViewportAttributes&& newAttributes) +{ + if (newAttributes.layoutSize.isEmpty()) { + resetViewportToDefaultState(); + return; + } + + m_hasViewportAttribute = true; + + m_rawAttributes = WTFMove(newAttributes); + m_allowsUserScaling = m_rawAttributes.userScalable; + m_initiallyFitToViewport = m_rawAttributes.initialScale < 0; + + if (!m_initiallyFitToViewport) + restrictScaleFactorToInitialScaleIfNotUserScalable(m_rawAttributes); + + updateMinimumScaleToFit(); +} + +void SimpleViewportController::didScroll(const IntPoint& position) +{ + m_contentsPosition = position; +} + +FloatRect SimpleViewportController::visibleContentsRect() const +{ + if (m_viewportSize.isEmpty() || m_contentsSize.isEmpty()) + return { }; + + FloatRect visibleContentsRect(boundContentsPosition(m_contentsPosition), visibleContentsSize()); + visibleContentsRect.intersect(FloatRect(FloatPoint::zero(), m_contentsSize)); + return visibleContentsRect; +} + +FloatSize SimpleViewportController::visibleContentsSize() const +{ + return FloatSize(m_viewportSize.width() / m_pageScaleFactor, m_viewportSize.height() / m_pageScaleFactor); +} + +FloatPoint SimpleViewportController::boundContentsPositionAtScale(const FloatPoint& framePosition, float scale) const +{ + // We need to floor the viewport here as to allow aligning the content in device units. If not, + // it might not be possible to scroll the last pixel and that affects fixed position elements. + return FloatPoint( + clampTo(framePosition.x(), .0f, std::max(.0f, m_contentsSize.width() - floorf(m_viewportSize.width() / scale))), + clampTo(framePosition.y(), .0f, std::max(.0f, m_contentsSize.height() - floorf(m_viewportSize.height() / scale)))); +} + +FloatPoint SimpleViewportController::boundContentsPosition(const FloatPoint& framePosition) const +{ + return boundContentsPositionAtScale(framePosition, m_pageScaleFactor); +} + +bool fuzzyCompare(float a, float b, float epsilon) +{ + return std::abs(a - b) < epsilon; +} + +bool SimpleViewportController::updateMinimumScaleToFit() +{ + if (m_viewportSize.isEmpty() || m_contentsSize.isEmpty() || !m_hasViewportAttribute) + return false; + + bool currentlyScaledToFit = fuzzyCompare(m_pageScaleFactor, m_minimumScaleToFit, 0.0001); + + float minimumScale = computeMinimumScaleFactorForContentContained(m_rawAttributes, roundedIntSize(m_viewportSize), roundedIntSize(m_contentsSize)); + + if (minimumScale <= 0) + return false; + + if (!fuzzyCompare(minimumScale, m_minimumScaleToFit, 0.0001)) { + m_minimumScaleToFit = minimumScale; + + if (currentlyScaledToFit) + m_pageScaleFactor = m_minimumScaleToFit; + else { + // Ensure the effective scale stays within bounds. + float boundedScale = innerBoundedViewportScale(m_pageScaleFactor); + if (!fuzzyCompare(boundedScale, m_pageScaleFactor, 0.0001)) + m_pageScaleFactor = boundedScale; + } + + return true; + } + return false; +} + +float SimpleViewportController::innerBoundedViewportScale(float viewportScale) const +{ + return clampTo(viewportScale, m_minimumScaleToFit, m_rawAttributes.maximumScale); +} + +void SimpleViewportController::resetViewportToDefaultState() +{ + m_hasViewportAttribute = false; + m_pageScaleFactor = 1; + m_minimumScaleToFit = 1; + + // Initializing Viewport Raw Attributes to avoid random negative or infinity scale factors + // if there is a race condition between the first layout and setting the viewport attributes for the first time. + m_rawAttributes.minimumScale = 1; + m_rawAttributes.maximumScale = 1; + m_rawAttributes.userScalable = m_allowsUserScaling; + + // The initial scale might be implicit and set to -1, in this case we have to infer it + // using the viewport size and the final layout size. + // To be able to assert for valid scale we initialize it to -1. + m_rawAttributes.initialScale = -1; +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS_THREADED) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.h b/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.h new file mode 100644 index 000000000..0bd1a3587 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2011, 2012 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * Copyright (C) 2014 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SimpleViewportController_h +#define SimpleViewportController_h + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include <WebCore/FloatPoint.h> +#include <WebCore/FloatRect.h> +#include <WebCore/FloatSize.h> +#include <WebCore/IntRect.h> +#include <WebCore/IntSize.h> +#include <WebCore/ViewportArguments.h> +#include <wtf/Noncopyable.h> + +namespace WebKit { + +class SimpleViewportController { + WTF_MAKE_NONCOPYABLE(SimpleViewportController); +public: + SimpleViewportController(const WebCore::IntSize&); + + void didChangeViewportSize(const WebCore::IntSize&); + void didChangeContentsSize(const WebCore::IntSize&); + void didChangeViewportAttributes(WebCore::ViewportAttributes&&); + void didScroll(const WebCore::IntPoint&); + + WebCore::FloatRect visibleContentsRect() const; + float pageScaleFactor() const { return m_pageScaleFactor; } + +private: + WebCore::FloatSize visibleContentsSize() const; + + void applyScaleAfterRenderingContents(float scale); + void applyPositionAfterRenderingContents(const WebCore::FloatPoint& pos); + + WebCore::FloatPoint boundContentsPosition(const WebCore::FloatPoint&) const; + WebCore::FloatPoint boundContentsPositionAtScale(const WebCore::FloatPoint&, float scale) const; + + bool updateMinimumScaleToFit(); + float innerBoundedViewportScale(float) const; + + void resetViewportToDefaultState(); + + WebCore::IntPoint m_contentsPosition; + WebCore::FloatSize m_contentsSize; + WebCore::FloatSize m_viewportSize; + float m_pageScaleFactor { 1 }; + + bool m_allowsUserScaling { false }; + float m_minimumScaleToFit { 1 }; + bool m_initiallyFitToViewport { false }; + + bool m_hasViewportAttribute { false }; + WebCore::ViewportAttributes m_rawAttributes; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS_THREADED) + +#endif // SimpleViewportController_h diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/WebCoordinatedSurface.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/WebCoordinatedSurface.cpp new file mode 100644 index 000000000..0ad1e7f86 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/WebCoordinatedSurface.cpp @@ -0,0 +1,131 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebCoordinatedSurface.h" + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedGraphicsArgumentCoders.h" +#include "GraphicsContext.h" +#include "WebCoreArgumentCoders.h" +#include <WebCore/GraphicsSurfaceToken.h> + +#if USE(TEXTURE_MAPPER) +#include "BitmapTextureGL.h" +#include "TextureMapperGL.h" +#endif + +using namespace WebCore; + +namespace WebKit { + +WebCoordinatedSurface::Handle::Handle() +{ +} + +void WebCoordinatedSurface::Handle::encode(IPC::Encoder& encoder) const +{ + encoder << m_size << m_flags; + encoder << m_bitmapHandle; +} + +bool WebCoordinatedSurface::Handle::decode(IPC::Decoder& decoder, Handle& handle) +{ + if (!decoder.decode(handle.m_size)) + return false; + if (!decoder.decode(handle.m_flags)) + return false; + if (!decoder.decode(handle.m_bitmapHandle)) + return false; + + return true; +} + +RefPtr<WebCoordinatedSurface> WebCoordinatedSurface::create(const IntSize& size, CoordinatedSurface::Flags flags) +{ + if (auto bitmap = ShareableBitmap::createShareable(size, (flags & SupportsAlpha) ? ShareableBitmap::SupportsAlpha : ShareableBitmap::NoFlags)) + return create(size, flags, WTFMove(bitmap)); + + return nullptr; +} + +std::unique_ptr<GraphicsContext> WebCoordinatedSurface::createGraphicsContext(const IntRect& rect) +{ + ASSERT(m_bitmap); + auto graphicsContext = m_bitmap->createGraphicsContext(); + graphicsContext->clip(rect); + graphicsContext->translate(rect.x(), rect.y()); + return graphicsContext; +} + +Ref<WebCoordinatedSurface> WebCoordinatedSurface::create(const IntSize& size, CoordinatedSurface::Flags flags, RefPtr<ShareableBitmap> bitmap) +{ + return adoptRef(*new WebCoordinatedSurface(size, flags, bitmap)); +} + +WebCoordinatedSurface::WebCoordinatedSurface(const IntSize& size, CoordinatedSurface::Flags flags, RefPtr<ShareableBitmap> bitmap) + : CoordinatedSurface(size, flags) + , m_bitmap(bitmap) +{ +} + +WebCoordinatedSurface::~WebCoordinatedSurface() +{ +} + +RefPtr<WebCoordinatedSurface> WebCoordinatedSurface::create(const Handle& handle) +{ + RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(handle.m_bitmapHandle); + if (!bitmap) + return nullptr; + + return create(handle.m_size, handle.m_flags, WTFMove(bitmap)); +} + +bool WebCoordinatedSurface::createHandle(Handle& handle) +{ + handle.m_size = m_size; + handle.m_flags = m_flags; + + if (!m_bitmap->createHandle(handle.m_bitmapHandle)) + return false; + + return true; +} + +void WebCoordinatedSurface::paintToSurface(const IntRect& rect, CoordinatedSurface::Client& client) +{ + auto context = createGraphicsContext(rect); + client.paintToSurfaceContext(*context); +} + +#if USE(TEXTURE_MAPPER) +void WebCoordinatedSurface::copyToTexture(RefPtr<WebCore::BitmapTexture> passTexture, const IntRect& target, const IntPoint& sourceOffset) +{ + RefPtr<BitmapTexture> texture(passTexture); + + ASSERT(m_bitmap); + RefPtr<Image> image = m_bitmap->createImage(); + texture->updateContents(image.get(), target, sourceOffset, BitmapTexture::UpdateCanModifyOriginalImageData); +} +#endif // USE(TEXTURE_MAPPER) + +} // namespace WebKit +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/WebCoordinatedSurface.h b/Source/WebKit2/Shared/CoordinatedGraphics/WebCoordinatedSurface.h new file mode 100644 index 000000000..88a0c1059 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/WebCoordinatedSurface.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef WebCoordinatedSurface_h +#define WebCoordinatedSurface_h + +#if USE(COORDINATED_GRAPHICS) +#include "ShareableBitmap.h" +#include <WebCore/CoordinatedSurface.h> + +namespace WebCore { +class BitmapTexture; +class GraphicsContext; +} + +namespace WebKit { + +class WebCoordinatedSurface : public WebCore::CoordinatedSurface { +public: + class Handle { + WTF_MAKE_NONCOPYABLE(Handle); + public: + Handle(); + + void encode(IPC::Encoder&) const; + static bool decode(IPC::Decoder&, Handle&); + + private: + friend class WebCoordinatedSurface; + mutable ShareableBitmap::Handle m_bitmapHandle; + WebCore::IntSize m_size; + WebCore::CoordinatedSurface::Flags m_flags; + }; + + // Create a new WebCoordinatedSurface, and allocate either a GraphicsSurface or a ShareableBitmap as backing. + static RefPtr<WebCoordinatedSurface> create(const WebCore::IntSize&, Flags); + + // Create a shareable surface from a handle. + static RefPtr<WebCoordinatedSurface> create(const Handle&); + + // Create a handle. + bool createHandle(Handle&); + + virtual ~WebCoordinatedSurface(); + + void paintToSurface(const WebCore::IntRect&, WebCore::CoordinatedSurface::Client&) override; + +#if USE(TEXTURE_MAPPER) + void copyToTexture(RefPtr<WebCore::BitmapTexture>, const WebCore::IntRect& target, const WebCore::IntPoint& sourceOffset) override; +#endif + +private: + WebCoordinatedSurface(const WebCore::IntSize&, Flags, RefPtr<ShareableBitmap>); + + // Create a WebCoordinatedSurface referencing an existing ShareableBitmap. + static Ref<WebCoordinatedSurface> create(const WebCore::IntSize&, Flags, RefPtr<ShareableBitmap>); + + std::unique_ptr<WebCore::GraphicsContext> createGraphicsContext(const WebCore::IntRect&); + + RefPtr<ShareableBitmap> m_bitmap; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) +#endif // WebCoordinatedSurface_h diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp new file mode 100644 index 000000000..a6eee3fd9 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2014 Igalia S.L. + * + * 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 "config.h" +#include "CompositingRunLoop.h" + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include <wtf/HashMap.h> +#include <wtf/MainThread.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/WorkQueue.h> + +#if USE(GLIB_EVENT_LOOP) +#include <glib.h> +#endif + +namespace WebKit { + +class WorkQueuePool { + WTF_MAKE_NONCOPYABLE(WorkQueuePool); + friend class NeverDestroyed<WorkQueuePool>; +public: + static WorkQueuePool& singleton() + { + ASSERT(isMainThread()); + static NeverDestroyed<WorkQueuePool> workQueuePool; + return workQueuePool; + } + + void dispatch(void* context, Function<void ()>&& function) + { + ASSERT(isMainThread()); + getOrCreateWorkQueueForContext(context).dispatch(WTFMove(function)); + } + + RunLoop& runLoop(void* context) + { + return getOrCreateWorkQueueForContext(context).runLoop(); + } + + void invalidate(void* context) + { + auto workQueue = m_workQueueMap.take(context); + ASSERT(workQueue); + if (m_workQueueMap.isEmpty()) { + m_sharedWorkQueue = nullptr; + m_threadCount = 0; + } else if (workQueue->hasOneRef()) + m_threadCount--; + } + +private: + WorkQueuePool() + { +#if PLATFORM(GTK) + m_threadCountLimit = 1; +#else + m_threadCountLimit = std::numeric_limits<unsigned>::max(); +#endif + } + + WorkQueue& getOrCreateWorkQueueForContext(void* context) + { + auto addResult = m_workQueueMap.add(context, nullptr); + if (addResult.isNewEntry) { + // FIXME: This is OK for now, and it works for a single-thread limit. But for configurations where more (but not unlimited) + // threads could be used, one option would be to use a HashSet here and disperse the contexts across the available threads. + if (m_threadCount >= m_threadCountLimit) { + ASSERT(m_sharedWorkQueue); + addResult.iterator->value = m_sharedWorkQueue; + } else { + addResult.iterator->value = WorkQueue::create("org.webkit.ThreadedCompositorWorkQueue"); + if (!m_threadCount) + m_sharedWorkQueue = addResult.iterator->value; + m_threadCount++; + } + } + + return *addResult.iterator->value; + } + + HashMap<void*, RefPtr<WorkQueue>> m_workQueueMap; + RefPtr<WorkQueue> m_sharedWorkQueue; + unsigned m_threadCount { 0 }; + unsigned m_threadCountLimit; +}; + +CompositingRunLoop::CompositingRunLoop(std::function<void ()>&& updateFunction) + : m_updateTimer(WorkQueuePool::singleton().runLoop(this), this, &CompositingRunLoop::updateTimerFired) + , m_updateFunction(WTFMove(updateFunction)) +{ +#if USE(GLIB_EVENT_LOOP) + m_updateTimer.setPriority(G_PRIORITY_HIGH_IDLE); +#endif +} + +CompositingRunLoop::~CompositingRunLoop() +{ + ASSERT(isMainThread()); + // Make sure the WorkQueue is deleted after the CompositingRunLoop, because m_updateTimer has a reference + // of the WorkQueue run loop. Passing this is not a problem because the pointer will only be used as a + // HashMap key by WorkQueuePool. + RunLoop::main().dispatch([context = this] { WorkQueuePool::singleton().invalidate(context); }); +} + +void CompositingRunLoop::performTask(Function<void ()>&& function) +{ + ASSERT(isMainThread()); + WorkQueuePool::singleton().dispatch(this, WTFMove(function)); +} + +void CompositingRunLoop::performTaskSync(Function<void ()>&& function) +{ + ASSERT(isMainThread()); + LockHolder locker(m_dispatchSyncConditionMutex); + WorkQueuePool::singleton().dispatch(this, [this, function = WTFMove(function)] { + function(); + LockHolder locker(m_dispatchSyncConditionMutex); + m_dispatchSyncCondition.notifyOne(); + }); + m_dispatchSyncCondition.wait(m_dispatchSyncConditionMutex); +} + +void CompositingRunLoop::startUpdateTimer(UpdateTiming timing) +{ + if (m_updateTimer.isActive()) + return; + + const static double targetFPS = 60; + double nextUpdateTime = 0; + if (timing == WaitUntilNextFrame) + nextUpdateTime = std::max((1 / targetFPS) - (monotonicallyIncreasingTime() - m_lastUpdateTime), 0.0); + + m_updateTimer.startOneShot(nextUpdateTime); +} + +void CompositingRunLoop::stopUpdateTimer() +{ + m_updateTimer.stop(); +} + +void CompositingRunLoop::updateTimerFired() +{ + m_updateFunction(); + m_lastUpdateTime = monotonicallyIncreasingTime(); +} + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS_THREADED) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h new file mode 100644 index 000000000..52b5d7d10 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 Igalia S.L. + * + * 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. + */ + +#ifndef CompositingRunLoop_h +#define CompositingRunLoop_h + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include <wtf/Condition.h> +#include <wtf/FastMalloc.h> +#include <wtf/Function.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/Noncopyable.h> +#include <wtf/RunLoop.h> + +namespace WebKit { + +class CompositingRunLoop { + WTF_MAKE_NONCOPYABLE(CompositingRunLoop); + WTF_MAKE_FAST_ALLOCATED; +public: + enum UpdateTiming { + Immediate, + WaitUntilNextFrame, + }; + + CompositingRunLoop(std::function<void ()>&&); + ~CompositingRunLoop(); + + void performTask(Function<void ()>&&); + void performTaskSync(Function<void ()>&&); + + void startUpdateTimer(UpdateTiming = Immediate); + void stopUpdateTimer(); + +private: + void updateTimerFired(); + + RunLoop::Timer<CompositingRunLoop> m_updateTimer; + std::function<void ()> m_updateFunction; + Lock m_dispatchSyncConditionMutex; + Condition m_dispatchSyncCondition; + + double m_lastUpdateTime { 0 }; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS_THREADED) + +#endif // CompositingRunLoop_h diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp new file mode 100644 index 000000000..54b7ef96f --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 Igalia S.L. + * + * 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 "config.h" + +#if USE(COORDINATED_GRAPHICS) +#include "ThreadSafeCoordinatedSurface.h" + +#include <WebCore/TextureMapperGL.h> +#include <wtf/StdLibExtras.h> + +using namespace WebCore; + +namespace WebKit { + +Ref<ThreadSafeCoordinatedSurface> ThreadSafeCoordinatedSurface::create(const IntSize& size, CoordinatedSurface::Flags flags) +{ + // Making an unconditionally unaccelerated buffer here is OK because this code + // isn't used by any platforms that respect the accelerated bit. + return adoptRef(*new ThreadSafeCoordinatedSurface(size, flags, ImageBuffer::create(size, Unaccelerated))); +} + +ThreadSafeCoordinatedSurface::ThreadSafeCoordinatedSurface(const IntSize& size, CoordinatedSurface::Flags flags, std::unique_ptr<ImageBuffer> buffer) + : CoordinatedSurface(size, flags) + , m_imageBuffer(WTFMove(buffer)) +{ +} + +ThreadSafeCoordinatedSurface::~ThreadSafeCoordinatedSurface() +{ +} + +void ThreadSafeCoordinatedSurface::paintToSurface(const IntRect& rect, CoordinatedSurface::Client& client) +{ + GraphicsContext& context = beginPaint(rect); + client.paintToSurfaceContext(context); + endPaint(); +} + +GraphicsContext& ThreadSafeCoordinatedSurface::beginPaint(const IntRect& rect) +{ + ASSERT(m_imageBuffer); + GraphicsContext& graphicsContext = m_imageBuffer->context(); + graphicsContext.save(); + graphicsContext.clip(rect); + graphicsContext.translate(rect.x(), rect.y()); + return graphicsContext; +} + +void ThreadSafeCoordinatedSurface::endPaint() +{ + ASSERT(m_imageBuffer); + m_imageBuffer->context().restore(); +} + +void ThreadSafeCoordinatedSurface::copyToTexture(RefPtr<BitmapTexture> texture, const IntRect& target, const IntPoint& sourceOffset) +{ + ASSERT(m_imageBuffer); + RefPtr<Image> image = m_imageBuffer->copyImage(DontCopyBackingStore); + texture->updateContents(image.get(), target, sourceOffset, BitmapTexture::UpdateCanModifyOriginalImageData); +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h new file mode 100644 index 000000000..f460eaa01 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Igalia S.L. + * + * 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. + */ + +#ifndef ThreadSafeCoordinatedSurface_h +#define ThreadSafeCoordinatedSurface_h + +#if USE(COORDINATED_GRAPHICS) +#include <WebCore/CoordinatedSurface.h> +#include <WebCore/ImageBuffer.h> + +namespace WebKit { + +class ThreadSafeCoordinatedSurface : public WebCore::CoordinatedSurface { +public: + virtual ~ThreadSafeCoordinatedSurface(); + + // Create a new ThreadSafeCoordinatedSurface and allocate either a GraphicsSurface or a ImageBuffer as backing. + static Ref<ThreadSafeCoordinatedSurface> create(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags); + + void paintToSurface(const WebCore::IntRect&, WebCore::CoordinatedSurface::Client&) override; + void copyToTexture(RefPtr<WebCore::BitmapTexture>, const WebCore::IntRect& target, const WebCore::IntPoint& sourceOffset) override; + +private: + ThreadSafeCoordinatedSurface(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags, std::unique_ptr<WebCore::ImageBuffer>); + + WebCore::GraphicsContext& beginPaint(const WebCore::IntRect&); + void endPaint(); + + std::unique_ptr<WebCore::ImageBuffer> m_imageBuffer; +}; + +} // namespace WebKit + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // ThreadSafeCoordinatedSurface_h diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp new file mode 100644 index 000000000..c7ad837c8 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2014 Igalia S.L. + * + * 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 "config.h" +#include "ThreadedCompositor.h" + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include "CompositingRunLoop.h" +#include <WebCore/PlatformDisplay.h> +#include <WebCore/TransformationMatrix.h> + +#if USE(OPENGL_ES_2) +#include <GLES2/gl2.h> +#else +#include <GL/gl.h> +#endif + +using namespace WebCore; + +namespace WebKit { + +Ref<ThreadedCompositor> ThreadedCompositor::create(Client& client, const IntSize& viewportSize, float scaleFactor, uint64_t nativeSurfaceHandle, ShouldDoFrameSync doFrameSync, TextureMapper::PaintFlags paintFlags) +{ + return adoptRef(*new ThreadedCompositor(client, viewportSize, scaleFactor, nativeSurfaceHandle, doFrameSync, paintFlags)); +} + +ThreadedCompositor::ThreadedCompositor(Client& client, const IntSize& viewportSize, float scaleFactor, uint64_t nativeSurfaceHandle, ShouldDoFrameSync doFrameSync, TextureMapper::PaintFlags paintFlags) + : m_client(client) + , m_viewportSize(viewportSize) + , m_scaleFactor(scaleFactor) + , m_nativeSurfaceHandle(nativeSurfaceHandle) + , m_doFrameSync(doFrameSync) + , m_paintFlags(paintFlags) + , m_needsResize(!viewportSize.isEmpty()) + , m_compositingRunLoop(std::make_unique<CompositingRunLoop>([this] { renderLayerTree(); })) +{ + m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this)] { + m_scene = adoptRef(new CoordinatedGraphicsScene(this)); + if (m_nativeSurfaceHandle) { + createGLContext(); + m_scene->setActive(true); + } else + m_scene->setActive(false); + }); +} + +ThreadedCompositor::~ThreadedCompositor() +{ +} + +void ThreadedCompositor::createGLContext() +{ + ASSERT(!isMainThread()); + ASSERT(m_nativeSurfaceHandle); + + m_context = GLContext::createContextForWindow(reinterpret_cast<GLNativeWindowType>(m_nativeSurfaceHandle), &PlatformDisplay::sharedDisplayForCompositing()); + if (!m_context) + return; + + if (m_doFrameSync == ShouldDoFrameSync::No) { + if (m_context->makeContextCurrent()) + m_context->swapInterval(0); + } +} + +void ThreadedCompositor::invalidate() +{ + m_scene->detach(); + m_compositingRunLoop->stopUpdateTimer(); + m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this)] { + m_scene->purgeGLResources(); + m_context = nullptr; + m_scene = nullptr; + }); + m_compositingRunLoop = nullptr; +} + +void ThreadedCompositor::setNativeSurfaceHandleForCompositing(uint64_t handle) +{ + m_compositingRunLoop->stopUpdateTimer(); + m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this), handle] { + // A new native handle can't be set without destroying the previous one first if any. + ASSERT(!!handle ^ !!m_nativeSurfaceHandle); + m_nativeSurfaceHandle = handle; + if (m_nativeSurfaceHandle) { + createGLContext(); + m_scene->setActive(true); + } else { + m_scene->setActive(false); + m_context = nullptr; + } + }); +} + +void ThreadedCompositor::setScaleFactor(float scale) +{ + m_compositingRunLoop->performTask([this, protectedThis = makeRef(*this), scale] { + m_scaleFactor = scale; + scheduleDisplayImmediately(); + }); +} + +void ThreadedCompositor::setScrollPosition(const IntPoint& scrollPosition, float scale) +{ + m_compositingRunLoop->performTask([this, protectedThis = makeRef(*this), scrollPosition, scale] { + m_scrollPosition = scrollPosition; + m_scaleFactor = scale; + scheduleDisplayImmediately(); + }); +} + +void ThreadedCompositor::setViewportSize(const IntSize& viewportSize, float scale) +{ + m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this), viewportSize, scale] { + m_viewportSize = viewportSize; + m_scaleFactor = scale; + m_needsResize = true; + scheduleDisplayImmediately(); + }); +} + +void ThreadedCompositor::setDrawsBackground(bool drawsBackground) +{ + m_compositingRunLoop->performTask([this, protectedThis = Ref<ThreadedCompositor>(*this), drawsBackground] { + m_drawsBackground = drawsBackground; + scheduleDisplayImmediately(); + }); +} + +void ThreadedCompositor::renderNextFrame() +{ + ASSERT(isMainThread()); + m_client.renderNextFrame(); +} + +void ThreadedCompositor::commitScrollOffset(uint32_t layerID, const IntSize& offset) +{ + ASSERT(isMainThread()); + m_client.commitScrollOffset(layerID, offset); +} + +void ThreadedCompositor::updateViewport() +{ + m_compositingRunLoop->startUpdateTimer(CompositingRunLoop::WaitUntilNextFrame); +} + +void ThreadedCompositor::scheduleDisplayImmediately() +{ + m_compositingRunLoop->startUpdateTimer(CompositingRunLoop::Immediate); +} + +void ThreadedCompositor::forceRepaint() +{ + m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this)] { + renderLayerTree(); + }); +} + +void ThreadedCompositor::renderLayerTree() +{ + if (!m_scene || !m_scene->isActive()) + return; + + if (!m_context || !m_context->makeContextCurrent()) + return; + + if (m_needsResize) { + glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height()); + m_needsResize = false; + } + FloatRect clipRect(0, 0, m_viewportSize.width(), m_viewportSize.height()); + + TransformationMatrix viewportTransform; + viewportTransform.scale(m_scaleFactor); + viewportTransform.translate(-m_scrollPosition.x(), -m_scrollPosition.y()); + + if (!m_drawsBackground) { + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + } + + m_scene->paintToCurrentGLContext(viewportTransform, 1, clipRect, Color::transparent, !m_drawsBackground, m_scrollPosition, m_paintFlags); + + m_context->swapBuffers(); +} + +void ThreadedCompositor::updateSceneState(const CoordinatedGraphicsState& state) +{ + ASSERT(isMainThread()); + RefPtr<CoordinatedGraphicsScene> scene = m_scene; + m_scene->appendUpdate([scene, state] { + scene->commitSceneState(state); + }); + + scheduleDisplayImmediately(); +} + +} +#endif // USE(COORDINATED_GRAPHICS_THREADED) diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h new file mode 100644 index 000000000..bac81a396 --- /dev/null +++ b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Igalia S.L. + * + * 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. + */ + +#ifndef ThreadedCompositor_h +#define ThreadedCompositor_h + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include "CompositingRunLoop.h" +#include "CoordinatedGraphicsScene.h" +#include <WebCore/GLContext.h> +#include <WebCore/IntSize.h> +#include <WebCore/TextureMapper.h> +#include <wtf/FastMalloc.h> +#include <wtf/Noncopyable.h> +#include <wtf/ThreadSafeRefCounted.h> + +namespace WebCore { +struct CoordinatedGraphicsState; +} + +namespace WebKit { + +class CoordinatedGraphicsScene; +class CoordinatedGraphicsSceneClient; + +class ThreadedCompositor : public CoordinatedGraphicsSceneClient, public ThreadSafeRefCounted<ThreadedCompositor> { + WTF_MAKE_NONCOPYABLE(ThreadedCompositor); + WTF_MAKE_FAST_ALLOCATED; +public: + class Client { + public: + virtual void renderNextFrame() = 0; + virtual void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) = 0; + }; + + enum class ShouldDoFrameSync { No, Yes }; + + static Ref<ThreadedCompositor> create(Client&, const WebCore::IntSize&, float scaleFactor, uint64_t nativeSurfaceHandle = 0, ShouldDoFrameSync = ShouldDoFrameSync::Yes, WebCore::TextureMapper::PaintFlags = 0); + virtual ~ThreadedCompositor(); + + void setNativeSurfaceHandleForCompositing(uint64_t); + void setScaleFactor(float); + void setScrollPosition(const WebCore::IntPoint&, float scale); + void setViewportSize(const WebCore::IntSize&, float scale); + void setDrawsBackground(bool); + + void updateSceneState(const WebCore::CoordinatedGraphicsState&); + + void invalidate(); + + void forceRepaint(); + +private: + ThreadedCompositor(Client&, const WebCore::IntSize&, float scaleFactor, uint64_t nativeSurfaceHandle, ShouldDoFrameSync, WebCore::TextureMapper::PaintFlags); + + // CoordinatedGraphicsSceneClient + void renderNextFrame() override; + void updateViewport() override; + void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) override; + + void renderLayerTree(); + void scheduleDisplayImmediately(); + + void createGLContext(); + + Client& m_client; + RefPtr<CoordinatedGraphicsScene> m_scene; + std::unique_ptr<WebCore::GLContext> m_context; + + WebCore::IntSize m_viewportSize; + WebCore::IntPoint m_scrollPosition; + float m_scaleFactor { 1 }; + bool m_drawsBackground { true }; + uint64_t m_nativeSurfaceHandle; + ShouldDoFrameSync m_doFrameSync; + WebCore::TextureMapper::PaintFlags m_paintFlags { 0 }; + bool m_needsResize { false }; + + std::unique_ptr<CompositingRunLoop> m_compositingRunLoop; +}; + +} // namespace WebKit + +#endif + +#endif // ThreadedCompositor_h |