| /* |
| * 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::CompositingCoordinatesTopDown) |
| repaintCounterRect.setY(layerBounds.height() - (layerBounds.y() + repaintCounterRect.height())); |
| internalSetNeedsDisplay(&repaintCounterRect); |
| } |
| if (owner()->owner()->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { |
| 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 |