blob: ae2b06a4f4c8c74285cbf5f9dbf83247a9c7afd2 [file] [log] [blame]
/*
* Copyright (C) 2011, 2015 Apple Inc. All rights reserved.
*
* 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. ``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
* 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 "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);
// It's important to get the clip from the context, because it may be significantly
// smaller than the layer bounds (e.g. tiled layers)
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)
{
// We always update the repaint count, but we do not paint it for layers that
// only contain tiled backing layers. Those report their repaint counts themselves.
if (!owner() || owner()->usesTiledBackingLayer())
return;
CGColorRef backgroundColor = nullptr;
// Make the background of the counter the same as the border color,
// unless there is no border, then make it red
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;
// We assume a maximum of 4 digits and a font size of 18.
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)
{
// Remove all the current sublayers and add the passed layers
CACFLayerSetSublayers(owner()->platformLayer(), 0);
// Perform removeFromSuperLayer in a separate pass. CACF requires superlayer to
// be null or CACFLayerInsertSublayer silently fails.
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