blob: 9008c15c46d0c7df58658938561d94ada6537292 [file] [log] [blame]
/*
* Copyright (C) 2018 Metrological Group B.V.
* Copyright (C) 2018 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* HOLDER OR 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.
*/
#pragma once
#include "Color.h"
#include "FilterOperations.h"
#include "FloatPoint.h"
#include "FloatPoint3D.h"
#include "FloatRect.h"
#include "FloatSize.h"
#include "NicosiaAnimatedBackingStoreClient.h"
#include "NicosiaAnimation.h"
#include "NicosiaSceneIntegration.h"
#include "ScrollTypes.h"
#include "TransformationMatrix.h"
#include <wtf/Function.h>
#include <wtf/Lock.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/TypeCasts.h>
namespace Nicosia {
class PlatformLayer : public ThreadSafeRefCounted<PlatformLayer> {
public:
virtual ~PlatformLayer();
virtual bool isCompositionLayer() const { return false; }
virtual bool isContentLayer() const { return false; }
using LayerID = uint64_t;
LayerID id() const { return m_id; }
void setSceneIntegration(RefPtr<SceneIntegration>&& sceneIntegration)
{
Locker locker { m_state.lock };
m_state.sceneIntegration = WTFMove(sceneIntegration);
}
std::unique_ptr<SceneIntegration::UpdateScope> createUpdateScope()
{
Locker locker { m_state.lock };
if (m_state.sceneIntegration)
return m_state.sceneIntegration->createUpdateScope();
return nullptr;
}
protected:
explicit PlatformLayer(uint64_t);
uint64_t m_id;
struct {
Lock lock;
RefPtr<SceneIntegration> sceneIntegration;
} m_state;
};
class ContentLayer;
class BackingStore;
class ImageBacking;
class CompositionLayer : public PlatformLayer {
public:
class Impl {
public:
using Factory = Function<std::unique_ptr<Impl>(uint64_t, CompositionLayer&)>;
virtual ~Impl();
virtual bool isTextureMapperImpl() const { return false; }
};
static Ref<CompositionLayer> create(uint64_t id, const Impl::Factory& factory)
{
return adoptRef(*new CompositionLayer(id, factory));
}
virtual ~CompositionLayer();
bool isCompositionLayer() const override { return true; }
Impl& impl() const { return *m_impl; }
struct LayerState {
struct Delta {
Delta() = default;
union {
struct {
bool positionChanged : 1;
bool anchorPointChanged : 1;
bool sizeChanged : 1;
bool boundsOriginChanged : 1;
bool transformChanged : 1;
bool childrenTransformChanged : 1;
bool contentsRectChanged : 1;
bool contentsTilingChanged : 1;
bool contentsClippingRectChanged : 1;
bool opacityChanged : 1;
bool solidColorChanged : 1;
bool filtersChanged : 1;
bool backdropFiltersChanged : 1;
bool backdropFiltersRectChanged : 1;
bool animationsChanged : 1;
bool childrenChanged : 1;
bool maskChanged : 1;
bool replicaChanged : 1;
bool flagsChanged : 1;
bool contentLayerChanged : 1;
bool backingStoreChanged : 1;
bool imageBackingChanged : 1;
bool animatedBackingStoreClientChanged : 1;
bool repaintCounterChanged : 1;
bool debugBorderChanged : 1;
bool scrollingNodeChanged : 1;
};
uint32_t value { 0 };
};
} delta;
struct Flags {
Flags()
: contentsVisible(true)
, backfaceVisible(true)
{ }
union {
struct {
bool contentsOpaque : 1;
bool drawsContent : 1;
bool contentsVisible : 1;
bool backfaceVisible : 1;
bool masksToBounds : 1;
bool preserves3D : 1;
};
uint32_t value { 0 };
};
} flags;
WebCore::FloatPoint position;
WebCore::FloatPoint3D anchorPoint;
WebCore::FloatSize size;
WebCore::FloatPoint boundsOrigin;
WebCore::TransformationMatrix transform;
WebCore::TransformationMatrix childrenTransform;
WebCore::FloatRect contentsRect;
WebCore::FloatSize contentsTilePhase;
WebCore::FloatSize contentsTileSize;
WebCore::FloatRoundedRect contentsClippingRect;
float opacity { 0 };
WebCore::Color solidColor;
WebCore::FilterOperations filters;
// FIXME: Despite the name, this implementation is not
// TextureMapper-specific. Should be renamed when necessary.
Animations animations;
Vector<RefPtr<CompositionLayer>> children;
RefPtr<CompositionLayer> replica;
RefPtr<CompositionLayer> mask;
RefPtr<CompositionLayer> backdropLayer;
WebCore::FloatRoundedRect backdropFiltersRect;
RefPtr<ContentLayer> contentLayer;
RefPtr<BackingStore> backingStore;
RefPtr<ImageBacking> imageBacking;
RefPtr<AnimatedBackingStoreClient> animatedBackingStoreClient;
struct RepaintCounter {
unsigned count { 0 };
bool visible { false };
} repaintCounter;
struct DebugBorder {
WebCore::Color color;
float width { 0 };
bool visible { false };
} debugBorder;
WebCore::ScrollingNodeID scrollingNodeID { 0 };
};
template<typename T>
void updateState(const T& functor)
{
Locker locker { PlatformLayer::m_state.lock };
functor(m_state.pending);
}
template<typename T>
void flushState(const T& functor)
{
Locker locker { PlatformLayer::m_state.lock };
auto& pending = m_state.pending;
auto& staging = m_state.staging;
staging.delta.value |= pending.delta.value;
if (pending.delta.positionChanged)
staging.position = pending.position;
if (pending.delta.anchorPointChanged)
staging.anchorPoint = pending.anchorPoint;
if (pending.delta.sizeChanged)
staging.size = pending.size;
if (pending.delta.boundsOriginChanged)
staging.boundsOrigin = pending.boundsOrigin;
if (pending.delta.transformChanged)
staging.transform = pending.transform;
if (pending.delta.childrenTransformChanged)
staging.childrenTransform = pending.childrenTransform;
if (pending.delta.contentsRectChanged)
staging.contentsRect = pending.contentsRect;
if (pending.delta.contentsTilingChanged) {
staging.contentsTilePhase = pending.contentsTilePhase;
staging.contentsTileSize = pending.contentsTileSize;
}
if (pending.delta.contentsClippingRectChanged)
staging.contentsClippingRect = pending.contentsClippingRect;
if (pending.delta.opacityChanged)
staging.opacity = pending.opacity;
if (pending.delta.solidColorChanged)
staging.solidColor = pending.solidColor;
if (pending.delta.filtersChanged)
staging.filters = pending.filters;
if (pending.delta.backdropFiltersChanged)
staging.backdropLayer = pending.backdropLayer;
if (pending.delta.backdropFiltersRectChanged)
staging.backdropFiltersRect = pending.backdropFiltersRect;
if (pending.delta.animationsChanged)
staging.animations = pending.animations;
if (pending.delta.childrenChanged)
staging.children = pending.children;
if (pending.delta.maskChanged)
staging.mask = pending.mask;
if (pending.delta.replicaChanged)
staging.replica = pending.replica;
if (pending.delta.flagsChanged)
staging.flags.value = pending.flags.value;
if (pending.delta.repaintCounterChanged)
staging.repaintCounter = pending.repaintCounter;
if (pending.delta.debugBorderChanged)
staging.debugBorder = pending.debugBorder;
if (pending.delta.scrollingNodeChanged)
staging.scrollingNodeID = pending.scrollingNodeID;
if (pending.delta.backingStoreChanged)
staging.backingStore = pending.backingStore;
if (pending.delta.contentLayerChanged)
staging.contentLayer = pending.contentLayer;
if (pending.delta.imageBackingChanged)
staging.imageBacking = pending.imageBacking;
if (pending.delta.animatedBackingStoreClientChanged)
staging.animatedBackingStoreClient = pending.animatedBackingStoreClient;
pending.delta = { };
functor(staging);
}
template<typename T>
void commitState(const T& functor)
{
Locker locker { PlatformLayer::m_state.lock };
m_state.committed = m_state.staging;
m_state.staging.delta = { };
functor(m_state.committed);
}
template<typename T>
void accessPending(const T& functor)
{
Locker locker { PlatformLayer::m_state.lock };
functor(m_state.pending);
}
template<typename T>
void accessCommitted(const T& functor)
{
Locker locker { PlatformLayer::m_state.lock };
functor(m_state.committed);
}
private:
CompositionLayer(uint64_t, const Impl::Factory&);
std::unique_ptr<Impl> m_impl;
struct {
LayerState pending;
LayerState staging;
LayerState committed;
} m_state;
};
class ContentLayer : public PlatformLayer {
public:
class Impl {
public:
using Factory = Function<std::unique_ptr<Impl>(ContentLayer&)>;
virtual ~Impl();
virtual bool isTextureMapperImpl() const { return false; }
};
static Ref<ContentLayer> create(const Impl::Factory& factory)
{
return adoptRef(*new ContentLayer(factory));
}
virtual ~ContentLayer();
bool isContentLayer() const override { return true; }
Impl& impl() const { return *m_impl; }
private:
ContentLayer(const Impl::Factory&);
std::unique_ptr<Impl> m_impl;
};
class BackingStore : public ThreadSafeRefCounted<BackingStore> {
public:
class Impl {
public:
using Factory = Function<std::unique_ptr<Impl>(BackingStore&)>;
virtual ~Impl();
virtual bool isTextureMapperImpl() const { return false; }
};
static Ref<BackingStore> create(const Impl::Factory& factory)
{
return adoptRef(*new BackingStore(factory));
}
virtual ~BackingStore();
Impl& impl() const { return *m_impl; }
private:
BackingStore(const Impl::Factory&);
std::unique_ptr<Impl> m_impl;
};
class ImageBacking : public ThreadSafeRefCounted<ImageBacking> {
public:
class Impl {
public:
using Factory = Function<std::unique_ptr<Impl>(ImageBacking&)>;
virtual ~Impl();
virtual bool isTextureMapperImpl() const { return false; }
};
static Ref<ImageBacking> create(const Impl::Factory& factory)
{
return adoptRef(*new ImageBacking(factory));
}
virtual ~ImageBacking();
Impl& impl() const { return *m_impl; }
private:
ImageBacking(const Impl::Factory&);
std::unique_ptr<Impl> m_impl;
};
} // namespace Nicosia
#define SPECIALIZE_TYPE_TRAITS_NICOSIA_PLATFORMLAYER(ToClassName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \
static bool isType(const Nicosia::PlatformLayer& layer) { return layer.predicate; } \
SPECIALIZE_TYPE_TRAITS_END()
SPECIALIZE_TYPE_TRAITS_NICOSIA_PLATFORMLAYER(CompositionLayer, isCompositionLayer());
SPECIALIZE_TYPE_TRAITS_NICOSIA_PLATFORMLAYER(ContentLayer, isContentLayer());
#define SPECIALIZE_TYPE_TRAITS_NICOSIA_COMPOSITIONLAYER_IMPL(ToClassName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \
static bool isType(const Nicosia::CompositionLayer::Impl& impl) { return impl.predicate; } \
SPECIALIZE_TYPE_TRAITS_END()
#define SPECIALIZE_TYPE_TRAITS_NICOSIA_CONTENTLAYER_IMPL(ToClassName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \
static bool isType(const Nicosia::ContentLayer::Impl& impl) { return impl.predicate; } \
SPECIALIZE_TYPE_TRAITS_END()
#define SPECIALIZE_TYPE_TRAITS_NICOSIA_BACKINGSTORE_IMPL(ToClassName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \
static bool isType(const Nicosia::BackingStore::Impl& impl) { return impl.predicate; } \
SPECIALIZE_TYPE_TRAITS_END()
#define SPECIALIZE_TYPE_TRAITS_NICOSIA_IMAGEBACKING_IMPL(ToClassName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(Nicosia::ToClassName) \
static bool isType(const Nicosia::ImageBacking::Impl& impl) { return impl.predicate; } \
SPECIALIZE_TYPE_TRAITS_END()