PlatformCALayerWinInternal.cpp [plain text]
#include "config.h"
#include "PlatformCALayerWinInternal.h"
#if USE(CA)
#include "FontCascade.h"
#include "GraphicsContext.h"
#include "PlatformCALayer.h"
#include "TileController.h"
#include "TiledBacking.h"
#include <QuartzCore/CACFLayer.h>
#include <wtf/MainThread.h>
using namespace WebCore;
PlatformCALayerWinInternal::PlatformCALayerWinInternal(PlatformCALayer* owner)
: m_owner(owner)
{
}
PlatformCALayerWinInternal::~PlatformCALayerWinInternal() = default;
struct DisplayOnMainThreadContext {
RetainPtr<CACFLayerRef> layer;
RetainPtr<CGContextRef> context;
DisplayOnMainThreadContext(CACFLayerRef caLayer, CGContextRef caContext)
: layer(caLayer)
, context(caContext)
{
}
};
static void redispatchOnMainQueue(void* context)
{
ASSERT(isMainThread());
std::unique_ptr<DisplayOnMainThreadContext> retainedContext(reinterpret_cast<DisplayOnMainThreadContext*>(context));
if (!retainedContext)
return;
PlatformCALayerWinInternal* self = static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(retainedContext->layer.get()));
self->displayCallback(retainedContext->layer.get(), retainedContext->context.get());
}
static bool repaintCountersAreDrawnByGridController(PlatformCALayer::LayerType layerType)
{
return layerType == PlatformCALayer::LayerTypeTiledBackingTileLayer;
}
void PlatformCALayerWinInternal::displayCallback(CACFLayerRef caLayer, CGContextRef context)
{
if (!isMainThread()) {
dispatch_async_f(dispatch_get_main_queue(), new DisplayOnMainThreadContext(caLayer, context), redispatchOnMainQueue);
return;
}
if (!owner() || !owner()->owner())
return;
CGContextSaveGState(context);
CGRect layerBounds = owner()->bounds();
PlatformCALayer::LayerType layerType = owner()->layerType();
PlatformCALayerClient* client = owner()->owner();
GraphicsLayer::CompositingCoordinatesOrientation orientation = client->platformCALayerContentsOrientation();
PlatformCALayer::flipContext(context, layerBounds.size.height);
GraphicsContext graphicsContext(context);
CGRect clipBounds = CGContextGetClipBoundingBox(context);
IntRect clip(enclosingIntRect(clipBounds));
client->platformCALayerPaintContents(owner(), graphicsContext, clip, GraphicsLayerPaintNormal);
if (client->platformCALayerShowRepaintCounter(owner())
&& !repaintCountersAreDrawnByGridController(layerType)) {
int drawCount = client->platformCALayerIncrementRepaintCount(owner());
drawRepaintCounters(caLayer, context, layerBounds, drawCount);
}
CGContextRestoreGState(context);
client->platformCALayerLayerDidDisplay(owner());
}
void PlatformCALayerWinInternal::drawRepaintCounters(CACFLayerRef caLayer, CGContextRef context, CGRect layerBounds, int drawCount)
{
if (!owner() || owner()->usesTiledBackingLayer())
return;
CGColorRef backgroundColor = nullptr;
float borderWidth = CACFLayerGetBorderWidth(caLayer);
if (borderWidth > 0)
backgroundColor = CACFLayerGetBorderColor(caLayer);
else
backgroundColor = cachedCGColor(Color(255, 0, 0));
PlatformCALayer::drawRepaintIndicator(context, owner(), drawCount, backgroundColor);
}
void PlatformCALayerWinInternal::internalSetNeedsDisplay(const FloatRect* dirtyRect)
{
if (dirtyRect) {
CGRect rect = *dirtyRect;
CACFLayerSetNeedsDisplay(owner()->platformLayer(), &rect);
} else
CACFLayerSetNeedsDisplay(owner()->platformLayer(), nullptr);
}
void PlatformCALayerWinInternal::setNeedsDisplay()
{
internalSetNeedsDisplay(nullptr);
}
void PlatformCALayerWinInternal::setNeedsDisplayInRect(const FloatRect& dirtyRect)
{
if (!owner())
return;
ASSERT(owner()->layerType() != PlatformCALayer::LayerTypeTiledBackingLayer);
if (owner()->owner()) {
if (owner()->owner()->platformCALayerShowRepaintCounter(owner())) {
FloatRect layerBounds = owner()->bounds();
FloatRect repaintCounterRect = layerBounds;
repaintCounterRect.setWidth(80);
repaintCounterRect.setHeight(22);
if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesOrientation::TopDown)
repaintCounterRect.setY(layerBounds.height() - (layerBounds.y() + repaintCounterRect.height()));
internalSetNeedsDisplay(&repaintCounterRect);
}
if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesOrientation::TopDown) {
FloatRect flippedDirtyRect = dirtyRect;
flippedDirtyRect.setY(owner()->bounds().height() - (flippedDirtyRect.y() + flippedDirtyRect.height()));
internalSetNeedsDisplay(&flippedDirtyRect);
return;
}
}
internalSetNeedsDisplay(&dirtyRect);
owner()->setNeedsCommit();
}
void PlatformCALayerWinInternal::setSublayers(const PlatformCALayerList& list)
{
CACFLayerSetSublayers(owner()->platformLayer(), 0);
for (size_t i = 0; i < list.size(); i++)
CACFLayerRemoveFromSuperlayer(list[i]->platformLayer());
for (size_t i = 0; i < list.size(); i++)
CACFLayerInsertSublayer(owner()->platformLayer(), list[i]->platformLayer(), i);
owner()->setNeedsCommit();
}
void PlatformCALayerWinInternal::getSublayers(PlatformCALayerList& list) const
{
CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
if (!sublayers) {
list.clear();
return;
}
size_t count = CFArrayGetCount(sublayers);
list.resize(count);
for (size_t arrayIndex = 0; arrayIndex < count; ++arrayIndex)
list[arrayIndex] = PlatformCALayer::platformCALayer(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, arrayIndex)));
}
void PlatformCALayerWinInternal::removeAllSublayers()
{
CACFLayerSetSublayers(owner()->platformLayer(), nullptr);
owner()->setNeedsCommit();
}
void PlatformCALayerWinInternal::insertSublayer(PlatformCALayer& layer, size_t index)
{
index = std::min(index, sublayerCount());
layer.removeFromSuperlayer();
CACFLayerInsertSublayer(owner()->platformLayer(), layer.platformLayer(), index);
owner()->setNeedsCommit();
}
size_t PlatformCALayerWinInternal::sublayerCount() const
{
CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
return sublayers ? CFArrayGetCount(sublayers) : 0;
}
int PlatformCALayerWinInternal::indexOfSublayer(const PlatformCALayer* reference)
{
CACFLayerRef ref = reference->platformLayer();
if (!ref)
return -1;
CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
if (!sublayers)
return -1;
size_t n = CFArrayGetCount(sublayers);
for (size_t i = 0; i < n; ++i) {
if (CFArrayGetValueAtIndex(sublayers, i) == ref)
return i;
}
return -1;
}
PlatformCALayer* PlatformCALayerWinInternal::sublayerAtIndex(int index) const
{
CFArrayRef sublayers = CACFLayerGetSublayers(owner()->platformLayer());
if (!sublayers || index < 0 || CFArrayGetCount(sublayers) <= index)
return nullptr;
return PlatformCALayer::platformCALayer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))));
}
void PlatformCALayerWinInternal::setBounds(const FloatRect& rect)
{
if (CGRectEqualToRect(rect, owner()->bounds()))
return;
CACFLayerSetBounds(owner()->platformLayer(), rect);
owner()->setNeedsCommit();
}
void PlatformCALayerWinInternal::setFrame(const FloatRect& rect)
{
CGRect oldFrame = CACFLayerGetFrame(owner()->platformLayer());
if (CGRectEqualToRect(rect, oldFrame))
return;
CACFLayerSetFrame(owner()->platformLayer(), rect);
owner()->setNeedsCommit();
}
bool PlatformCALayerWinInternal::isOpaque() const
{
return CACFLayerIsOpaque(owner()->platformLayer());
}
void PlatformCALayerWinInternal::setOpaque(bool value)
{
CACFLayerSetOpaque(owner()->platformLayer(), value);
}
float PlatformCALayerWinInternal::contentsScale() const
{
#if HAVE(CACFLAYER_SETCONTENTSSCALE)
return CACFLayerGetContentsScale(owner()->platformLayer());
#else
return 1.0f;
#endif
}
void PlatformCALayerWinInternal::setContentsScale(float scaleFactor)
{
#if HAVE(CACFLAYER_SETCONTENTSSCALE)
CACFLayerSetContentsScale(owner()->platformLayer(), scaleFactor);
#endif
}
void PlatformCALayerWinInternal::setBorderWidth(float value)
{
CACFLayerSetBorderWidth(owner()->platformLayer(), value);
}
void PlatformCALayerWinInternal::setBorderColor(const Color& value)
{
CGFloat components[4] = { 0, 0, 0, 0 };
RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
if (value.isValid())
value.getRGBA(components[0], components[1], components[2], components[3]);
RetainPtr<CGColorRef> color = adoptCF(CGColorCreate(colorSpace.get(), components));
CACFLayerSetBorderColor(owner()->platformLayer(), color.get());
}
#endif