2
* Copyright (C) 2011 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
13
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23
* THE POSSIBILITY OF SUCH DAMAGE.
27
#import "BackingStore.h"
29
#import "CGUtilities.h"
30
#import "ShareableBitmap.h"
31
#import "UpdateInfo.h"
32
#import "WebPageProxy.h"
33
#import <WebCore/GraphicsContext.h>
34
#import <WebCore/Region.h>
36
using namespace WebCore;
40
void BackingStore::performWithScrolledRectTransform(const IntRect& rect, void (^block)(const IntRect&, const IntSize&))
42
if (m_scrolledRect.isEmpty() || m_scrolledRectOffset.isZero() || !m_scrolledRect.intersects(rect)) {
43
block(rect, IntSize());
47
// The part of rect that's outside the scrolled rect is not translated.
48
Region untranslatedRegion = rect;
49
untranslatedRegion.subtract(m_scrolledRect);
50
Vector<IntRect> untranslatedRects = untranslatedRegion.rects();
51
for (size_t i = 0; i < untranslatedRects.size(); ++i)
52
block(untranslatedRects[i], IntSize());
54
// The part of rect that intersects the scrolled rect comprises up to four parts, each subject
55
// to a different translation (all translations are equivalent modulo the dimensions of the
56
// scrolled rect to the scroll offset).
57
IntRect intersection = rect;
58
intersection.intersect(m_scrolledRect);
60
IntRect scrolledRect = m_scrolledRect;
61
IntSize offset = m_scrolledRectOffset;
62
scrolledRect.move(-offset);
64
IntRect part = intersection;
65
part.intersect(scrolledRect);
70
offset += IntSize(0, -m_scrolledRect.height());
71
scrolledRect.move(IntSize(0, m_scrolledRect.height()));
72
part.intersect(scrolledRect);
77
offset += IntSize(-m_scrolledRect.width(), 0);
78
scrolledRect.move(IntSize(m_scrolledRect.width(), 0));
79
part.intersect(scrolledRect);
84
offset += IntSize(0, m_scrolledRect.height());
85
scrolledRect.move(IntSize(0, -m_scrolledRect.height()));
86
part.intersect(scrolledRect);
91
void BackingStore::resetScrolledRect()
93
ASSERT(!m_scrolledRect.isEmpty());
95
if (m_scrolledRectOffset.isZero()) {
96
m_scrolledRect = IntRect();
100
IntSize scaledSize = m_scrolledRect.size();
101
scaledSize.scale(m_deviceScaleFactor);
103
RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
104
RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(0, scaledSize.width(), scaledSize.height(), 8, scaledSize.width() * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
106
CGContextScaleCTM(context.get(), m_deviceScaleFactor, m_deviceScaleFactor);
108
CGContextScaleCTM(context.get(), 1, -1);
109
CGContextTranslateCTM(context.get(), -m_scrolledRect.x(), -m_scrolledRect.maxY());
110
paint(context.get(), m_scrolledRect);
112
IntRect sourceRect(IntPoint(), m_scrolledRect.size());
113
paintBitmapContext(backingStoreContext(), context.get(), m_deviceScaleFactor, m_scrolledRect.location(), sourceRect);
115
m_scrolledRect = IntRect();
116
m_scrolledRectOffset = IntSize();
119
void BackingStore::paint(PlatformGraphicsContext context, const IntRect& rect)
121
// FIXME: This is defined outside the block to work around bugs in llvm-gcc 4.2.
122
__block CGRect source;
123
performWithScrolledRectTransform(rect, ^(const IntRect& part, const IntSize& offset) {
125
CGContextSaveGState(context);
126
CGContextClipToRect(context, part);
128
CGContextScaleCTM(context, 1, -1);
129
CGContextDrawLayerAtPoint(context, CGPointMake(-offset.width(), offset.height() - m_size.height()), m_cgLayer.get());
131
CGContextRestoreGState(context);
135
ASSERT(m_bitmapContext);
137
source.origin.x += offset.width();
138
source.origin.y += offset.height();
139
paintBitmapContext(context, m_bitmapContext.get(), m_deviceScaleFactor, part.location(), source);
143
CGContextRef BackingStore::backingStoreContext()
146
return CGLayerGetContext(m_cgLayer.get());
148
// Try to create a layer.
149
if (CGContextRef containingWindowContext = m_webPageProxy->containingWindowGraphicsContext()) {
150
m_cgLayer.adoptCF(CGLayerCreateWithContext(containingWindowContext, m_size, 0));
151
CGContextRef layerContext = CGLayerGetContext(m_cgLayer.get());
153
CGContextSetBlendMode(layerContext, kCGBlendModeCopy);
155
// We want the origin to be in the top left corner so flip the backing store context.
156
CGContextTranslateCTM(layerContext, 0, m_size.height());
157
CGContextScaleCTM(layerContext, 1, -1);
159
if (m_bitmapContext) {
160
// Paint the contents of the bitmap into the layer context.
161
paintBitmapContext(layerContext, m_bitmapContext.get(), m_deviceScaleFactor, CGPointZero, CGRectMake(0, 0, m_size.width(), m_size.height()));
162
m_bitmapContext = nullptr;
168
if (!m_bitmapContext) {
169
RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
171
IntSize scaledSize(m_size);
172
scaledSize.scale(m_deviceScaleFactor);
173
m_bitmapContext.adoptCF(CGBitmapContextCreate(0, scaledSize.width(), scaledSize.height(), 8, scaledSize.width() * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
175
CGContextSetBlendMode(m_bitmapContext.get(), kCGBlendModeCopy);
177
CGContextScaleCTM(m_bitmapContext.get(), m_deviceScaleFactor, m_deviceScaleFactor);
179
// We want the origin to be in the top left corner so flip the backing store context.
180
CGContextTranslateCTM(m_bitmapContext.get(), 0, m_size.height());
181
CGContextScaleCTM(m_bitmapContext.get(), 1, -1);
184
return m_bitmapContext.get();
187
void BackingStore::incorporateUpdate(ShareableBitmap* bitmap, const UpdateInfo& updateInfo)
189
CGContextRef context = backingStoreContext();
191
scroll(updateInfo.scrollRect, updateInfo.scrollOffset);
193
IntPoint updateRectLocation = updateInfo.updateRectBounds.location();
195
GraphicsContext ctx(context);
196
__block GraphicsContext* graphicsContext = &ctx;
198
// Paint all update rects.
199
for (size_t i = 0; i < updateInfo.updateRects.size(); ++i) {
200
IntRect updateRect = updateInfo.updateRects[i];
201
IntRect srcRect = updateRect;
202
// FIXME: This is defined outside the block to work around bugs in llvm-gcc 4.2.
203
__block IntRect srcPart;
204
performWithScrolledRectTransform(srcRect, ^(const IntRect& part, const IntSize& offset) {
206
srcPart.move(-updateRectLocation.x(), -updateRectLocation.y());
207
bitmap->paint(*graphicsContext, updateInfo.deviceScaleFactor, part.location() + offset, srcPart);
212
void BackingStore::scroll(const IntRect& scrollRect, const IntSize& scrollOffset)
214
if (scrollOffset.isZero())
217
ASSERT(!scrollRect.isEmpty());
219
if (!m_scrolledRect.isEmpty() && m_scrolledRect != scrollRect)
222
m_scrolledRect = scrollRect;
224
int width = (m_scrolledRectOffset.width() - scrollOffset.width()) % m_scrolledRect.width();
226
width += m_scrolledRect.width();
227
m_scrolledRectOffset.setWidth(width);
229
int height = (m_scrolledRectOffset.height() - scrollOffset.height()) % m_scrolledRect.height();
231
height += m_scrolledRect.height();
232
m_scrolledRectOffset.setHeight(height);
235
} // namespace WebKit