[BlackBerry] Add WebPageCompositor class to BlackBerry WebKit API
[WebKit-https.git] / Source / WebKit / blackberry / Api / BackingStore.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2011 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "BackingStore.h"
21
22 #include "BackingStoreClient.h"
23 #include "BackingStoreCompositingSurface.h"
24 #include "BackingStoreTile.h"
25 #include "BackingStore_p.h"
26 #include "FatFingers.h"
27 #include "Frame.h"
28 #include "FrameView.h"
29 #include "GraphicsContext.h"
30 #include "InspectorController.h"
31 #include "Page.h"
32 #include "SurfacePool.h"
33 #include "WebPage.h"
34 #include "WebPageClient.h"
35 #include "WebPageCompositorClient.h"
36 #include "WebPageCompositor_p.h"
37 #include "WebPage_p.h"
38 #include "WebSettings.h"
39
40 #include <BlackBerryPlatformExecutableMessage.h>
41 #include <BlackBerryPlatformIntRectRegion.h>
42 #include <BlackBerryPlatformLog.h>
43 #include <BlackBerryPlatformMessage.h>
44 #include <BlackBerryPlatformMessageClient.h>
45 #include <BlackBerryPlatformWindow.h>
46
47 #include <wtf/CurrentTime.h>
48 #include <wtf/MathExtras.h>
49 #include <wtf/NotFound.h>
50
51 #define SUPPRESS_NON_VISIBLE_REGULAR_RENDER_JOBS 0
52 #define ENABLE_SCROLLBARS 1
53 #define ENABLE_REPAINTONSCROLL 1
54 #define DEBUG_BACKINGSTORE 0
55 #define DEBUG_CHECKERBOARD 0
56 #define DEBUG_WEBCORE_REQUESTS 0
57 #define DEBUG_VISUALIZE 0
58 #define DEBUG_TILEMATRIX 0
59 #define DEBUG_COMPOSITING_DIRTY_REGION 0
60
61 #include <BlackBerryPlatformScreen.h>
62
63 using namespace WebCore;
64 using namespace std;
65
66 using BlackBerry::Platform::Graphics::Window;
67 using BlackBerry::Platform::IntRect;
68 using BlackBerry::Platform::IntPoint;
69 using BlackBerry::Platform::IntSize;
70
71 namespace BlackBerry {
72 namespace WebKit {
73
74 const int s_renderTimerTimeout = 1.0;
75 WebPage* BackingStorePrivate::s_currentBackingStoreOwner = 0;
76
77 typedef std::pair<int, int> Divisor;
78 typedef Vector<Divisor> DivisorList;
79 // FIXME: Cache this and/or use a smarter algorithm.
80 static DivisorList divisors(unsigned n)
81 {
82     DivisorList divisors;
83     for (unsigned i = 1; i <= n; ++i)
84         if (!(n % i))
85             divisors.append(std::make_pair(i, n / i));
86     return divisors;
87 }
88
89 static bool divisorIsPerfectWidth(Divisor divisor, Platform::IntSize size, int tileWidth)
90 {
91     return size.width() <= divisor.first * tileWidth && abs(size.width() - divisor.first * tileWidth) < tileWidth;
92 }
93
94 static bool divisorIsPerfectHeight(Divisor divisor, Platform::IntSize size, int tileHeight)
95 {
96     return size.height() <= divisor.second * tileHeight && abs(size.height() - divisor.second * tileHeight) < tileHeight;
97 }
98
99 static bool divisorIsPreferredDirection(Divisor divisor, BackingStorePrivate::TileMatrixDirection direction)
100 {
101     if (direction == BackingStorePrivate::Vertical)
102         return divisor.second > divisor.first;
103     return divisor.first > divisor.second;
104 }
105
106 // Compute best divisor given the ratio determined by size.
107 static Divisor bestDivisor(Platform::IntSize size, int tileWidth, int tileHeight,
108                            int minimumNumberOfTilesWide, int minimumNumberOfTilesHigh,
109                            BackingStorePrivate::TileMatrixDirection direction)
110 {
111     // The point of this function is to determine the number of tiles in each
112     // dimension. We do this by looking to match the tile matrix width/height
113     // ratio as closely as possible with the width/height ratio of the contents.
114     // We also look at the direction passed to give preference to one dimension
115     // over another. This method could probably be made faster, but it gets the
116     // job done.
117     SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
118     ASSERT(!surfacePool->isEmpty());
119
120     // Store a static list of possible divisors.
121     static DivisorList divisorList = divisors(surfacePool->size());
122
123     // The ratio we're looking to best imitate.
124     float ratio = static_cast<float>(size.width()) / static_cast<float>(size.height());
125
126     Divisor bestDivisor;
127     for (size_t i = 0; i < divisorList.size(); ++i) {
128         Divisor divisor = divisorList[i];
129
130         const bool isPerfectWidth = divisorIsPerfectWidth(divisor, size, tileWidth);
131         const bool isPerfectHeight = divisorIsPerfectHeight(divisor, size, tileHeight);
132         const bool isValidWidth = divisor.first >= minimumNumberOfTilesWide || isPerfectWidth;
133         const bool isValidHeight = divisor.second >= minimumNumberOfTilesHigh || isPerfectHeight;
134         if (!isValidWidth || !isValidHeight)
135             continue;
136
137         if (isPerfectWidth || isPerfectHeight) {
138             bestDivisor = divisor; // Found a perfect fit!
139 #if DEBUG_TILEMATRIX
140             BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "bestDivisor found perfect size isPerfectWidth=%s isPerfectHeight=%s",
141                                    isPerfectWidth ? "true" : "false",
142                                    isPerfectHeight ? "true" : "false");
143 #endif
144             break;
145         }
146
147         // Store basis of comparison.
148         if (!bestDivisor.first || !bestDivisor.second) {
149             bestDivisor = divisor;
150             continue;
151         }
152
153         // If the current best divisor agrees with the preferred tile matrix direction,
154         // then continue if the current candidate does not.
155         if (divisorIsPreferredDirection(bestDivisor, direction) && !divisorIsPreferredDirection(divisor, direction))
156             continue;
157
158         // Compare ratios.
159         float diff1 = fabs((static_cast<float>(divisor.first) / static_cast<float>(divisor.second)) - ratio);
160         float diff2 = fabs((static_cast<float>(bestDivisor.first) / static_cast<float>(bestDivisor.second)) - ratio);
161         if (diff1 < diff2)
162             bestDivisor = divisor;
163     }
164
165     return bestDivisor;
166 }
167
168 struct BackingStoreMutexLocker {
169     BackingStoreMutexLocker(BackingStorePrivate* backingStorePrivate)
170         : m_backingStorePrivate(backingStorePrivate)
171     {
172         m_backingStorePrivate->lockBackingStore();
173     }
174
175     ~BackingStoreMutexLocker()
176     {
177         m_backingStorePrivate->unlockBackingStore();
178     }
179
180 private:
181     BackingStorePrivate* m_backingStorePrivate;
182 };
183
184 Platform::IntRect BackingStoreGeometry::backingStoreRect() const
185 {
186     return Platform::IntRect(backingStoreOffset(), backingStoreSize());
187 }
188
189 Platform::IntSize BackingStoreGeometry::backingStoreSize() const
190 {
191     return Platform::IntSize(numberOfTilesWide() * BackingStorePrivate::tileWidth(), numberOfTilesHigh() * BackingStorePrivate::tileHeight());
192 }
193
194 BackingStorePrivate::BackingStorePrivate()
195     : m_suspendScreenUpdates(false)
196     , m_suspendBackingStoreUpdates(false)
197     , m_suspendRenderJobs(false)
198     , m_suspendRegularRenderJobs(false)
199     , m_isScrollingOrZooming(false)
200     , m_webPage(0)
201     , m_client(0)
202     , m_renderQueue(adoptPtr(new RenderQueue(this)))
203     , m_defersBlit(true)
204     , m_hasBlitJobs(false)
205     , m_currentWindowBackBuffer(0)
206     , m_preferredTileMatrixDimension(Vertical)
207     , m_blitGeneration(-1)
208 #if USE(ACCELERATED_COMPOSITING)
209     , m_needsDrawLayersOnCommit(false)
210     , m_isDirectRenderingAnimationMessageScheduled(false)
211 #endif
212 {
213     m_frontState = reinterpret_cast<unsigned>(new BackingStoreGeometry);
214     m_backState = reinterpret_cast<unsigned>(new BackingStoreGeometry);
215
216     m_renderTimer = adoptPtr(new Timer<BackingStorePrivate>(this, &BackingStorePrivate::renderOnTimer));
217
218     // Need a recursive mutex to achieve a global lock.
219     pthread_mutexattr_t attr;
220     pthread_mutexattr_init(&attr);
221     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
222     pthread_mutex_init(&m_mutex, &attr);
223     pthread_mutexattr_destroy(&attr);
224
225     pthread_mutex_init(&m_blitGenerationLock, 0);
226     pthread_cond_init(&m_blitGenerationCond, 0);
227 }
228
229 BackingStorePrivate::~BackingStorePrivate()
230 {
231     BackingStoreGeometry* front = reinterpret_cast<BackingStoreGeometry*>(m_frontState);
232     delete front;
233     m_frontState = 0;
234
235     BackingStoreGeometry* back = reinterpret_cast<BackingStoreGeometry*>(m_backState);
236     delete back;
237     m_backState = 0;
238
239     pthread_cond_destroy(&m_blitGenerationCond);
240     pthread_mutex_destroy(&m_blitGenerationLock);
241     pthread_mutex_destroy(&m_mutex);
242 }
243
244 bool BackingStorePrivate::shouldDirectRenderingToWindow() const
245 {
246     if (m_webPage->settings()->isDirectRenderingToWindowEnabled() || !isActive())
247         return true;
248
249     const BackingStoreGeometry* currentState = frontState();
250     const unsigned tilesNecessary = minimumNumberOfTilesWide() * minimumNumberOfTilesHigh();
251     const unsigned tilesAvailable = currentState->numberOfTilesWide() * currentState->numberOfTilesHigh();
252     return tilesAvailable < tilesNecessary;
253 }
254
255 bool BackingStorePrivate::isOpenGLCompositing() const
256 {
257     if (Window* window = m_webPage->client()->window())
258         return window->windowUsage() == Window::GLES2Usage;
259
260     // If there's no window, OpenGL rendering is currently the only option.
261     return true;
262 }
263
264 void BackingStorePrivate::suspendScreenAndBackingStoreUpdates()
265 {
266     m_suspendBackingStoreUpdates = true;
267
268     // Make sure the user interface thread gets the message before we proceed
269     // because blitContents can be called from this thread and it must honor
270     // this flag.
271     m_suspendScreenUpdates = true;
272     BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
273
274 #if USE(ACCELERATED_COMPOSITING)
275     m_webPage->d->resetCompositingSurface();
276 #endif
277 }
278
279 void BackingStorePrivate::resumeScreenAndBackingStoreUpdates(BackingStore::ResumeUpdateOperation op)
280 {
281     m_suspendBackingStoreUpdates = false;
282
283 #if USE(ACCELERATED_COMPOSITING)
284     if (op != BackingStore::None)
285         m_webPage->d->setNeedsOneShotDrawingSynchronization();
286 #endif
287
288     // For the direct rendering case, there is no such operation as blit,
289     // we have to render to get anything to the screen.
290     if (shouldDirectRenderingToWindow() && op == BackingStore::Blit)
291         op = BackingStore::RenderAndBlit;
292
293     // Do some rendering if necessary.
294     if (op == BackingStore::RenderAndBlit)
295         renderVisibleContents();
296
297     // Make sure the user interface thread gets the message before we proceed
298     // because blitContents can be called from the user interface thread and
299     // it must honor this flag.
300     m_suspendScreenUpdates = false;
301     BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
302
303     // Do some blitting if necessary.
304     if ((op == BackingStore::Blit || op == BackingStore::RenderAndBlit) && !shouldDirectRenderingToWindow())
305         blitVisibleContents();
306 }
307
308 void BackingStorePrivate::repaint(const Platform::IntRect& windowRect,
309                                   bool contentChanged, bool immediate)
310 {
311     if (m_suspendBackingStoreUpdates)
312         return;
313
314      // If immediate is true, then we're being asked to perform synchronously.
315      // NOTE: WebCore::ScrollView will call this method with immediate:true and contentChanged:false.
316      // This is a special case introduced specifically for the Apple's windows port and can be safely ignored I believe.
317      // Now this method will be called from WebPagePrivate::repaint().
318
319     if (contentChanged && !windowRect.isEmpty()) {
320         // This windowRect is in untransformed coordinates relative to the viewport, but
321         // it needs to be transformed coordinates relative to the transformed contents.
322         Platform::IntRect rect = m_webPage->d->mapToTransformed(m_client->mapFromViewportToContents(windowRect));
323         rect.inflate(1 /*dx*/, 1 /*dy*/); // Account for anti-aliasing of previous rendering runs.
324
325         // FIXME: This should not explicitely depend on WebCore::.
326         WebCore::IntRect tmpRect = rect;
327         m_client->clipToTransformedContentsRect(tmpRect);
328
329         rect = tmpRect;
330         if (rect.isEmpty())
331             return;
332
333 #if DEBUG_WEBCORE_REQUESTS
334         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
335                                   "BackingStorePrivate::repaint rect=%d,%d %dx%d contentChanged=%s immediate=%s",
336                                   rect.x(), rect.y(), rect.width(), rect.height(),
337                                   (contentChanged ? "true" : "false"),
338                                   (immediate ? "true" : "false"));
339 #endif
340
341         if (immediate) {
342             if (render(rect) && !shouldDirectRenderingToWindow())
343                 blitVisibleContents();
344         } else
345             m_renderQueue->addToQueue(RenderQueue::RegularRender, rect);
346     }
347 }
348
349 void BackingStorePrivate::slowScroll(const Platform::IntSize& delta, const Platform::IntRect& windowRect, bool immediate)
350 {
351 #if DEBUG_BACKINGSTORE
352     // Start the time measurement...
353     double time = WTF::currentTime();
354 #endif
355
356     scrollingStartedHelper(delta);
357
358     // This windowRect is in untransformed coordinates relative to the viewport, but
359     // it needs to be transformed coordinates relative to the transformed contents.
360     Platform::IntRect rect = m_webPage->d->mapToTransformed(m_client->mapFromViewportToContents(windowRect));
361
362     if (immediate) {
363         if (render(rect) && !isSuspended() && !shouldDirectRenderingToWindow())
364             blitVisibleContents();
365     } else {
366         m_renderQueue->addToQueue(RenderQueue::VisibleScroll, rect);
367         // We only blit here if the client did not generate the scroll as the client
368         // now supports blitting asynchronously during scroll operations.
369         if (!m_client->isClientGeneratedScroll() && !shouldDirectRenderingToWindow())
370             blitVisibleContents();
371     }
372
373 #if DEBUG_BACKINGSTORE
374     // Stop the time measurement.
375     double elapsed = WTF::currentTime() - time;
376     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::slowScroll elapsed=%f", elapsed);
377 #endif
378 }
379
380 void BackingStorePrivate::scroll(const Platform::IntSize& delta,
381                                  const Platform::IntRect& scrollViewRect,
382                                  const Platform::IntRect& clipRect)
383 {
384     // If we are direct rendering then we are forced to go down the slow path
385     // to scrolling.
386     if (shouldDirectRenderingToWindow()) {
387         Platform::IntRect viewportRect(Platform::IntPoint(0, 0), m_webPage->d->transformedViewportSize());
388         slowScroll(delta, m_webPage->d->mapFromTransformed(viewportRect), true /*immediate*/);
389         return;
390     }
391
392 #if DEBUG_BACKINGSTORE
393     // Start the time measurement...
394     double time = WTF::currentTime();
395 #endif
396
397     scrollingStartedHelper(delta);
398
399     // We only blit here if the client did not generate the scroll as the client
400     // now supports blitting asynchronously during scroll operations.
401     if (!m_client->isClientGeneratedScroll())
402         blitVisibleContents();
403
404 #if DEBUG_BACKINGSTORE
405     // Stop the time measurement.
406     double elapsed = WTF::currentTime() - time;
407     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::scroll dx=%d, dy=%d elapsed=%f", delta.width(), delta.height(), elapsed);
408 #endif
409 }
410
411 void BackingStorePrivate::scrollingStartedHelper(const Platform::IntSize& delta)
412 {
413     // Notify the render queue so that it can shuffle accordingly.
414     m_renderQueue->updateSortDirection(delta.width(), delta.height());
415     m_renderQueue->visibleContentChanged(visibleContentsRect());
416
417     // Scroll the actual backingstore.
418     scrollBackingStore(delta.width(), delta.height());
419
420     // Add any newly visible tiles that have not been previously rendered to the queue
421     // and check if the tile was previously rendered by regular render job.
422     updateTilesForScrollOrNotRenderedRegion();
423 }
424
425 bool BackingStorePrivate::shouldSuppressNonVisibleRegularRenderJobs() const
426 {
427 #if SUPPRESS_NON_VISIBLE_REGULAR_RENDER_JOBS
428     return true;
429 #else
430     // Always suppress when loading as this drastically decreases page loading
431     // time...
432     return m_client->isLoading();
433 #endif
434 }
435
436 bool BackingStorePrivate::shouldPerformRenderJobs() const
437 {
438     return (m_webPage->isVisible() || shouldDirectRenderingToWindow()) && !m_suspendRenderJobs && !m_suspendBackingStoreUpdates && !m_renderQueue->isEmpty(!m_suspendRegularRenderJobs);
439 }
440
441 bool BackingStorePrivate::shouldPerformRegularRenderJobs() const
442 {
443     return shouldPerformRenderJobs() && !m_suspendRegularRenderJobs;
444 }
445
446 void BackingStorePrivate::startRenderTimer()
447 {
448     // Called when render queue has a new job added.
449     if (m_renderTimer->isActive() || m_renderQueue->isEmpty(!m_suspendRegularRenderJobs))
450         return;
451
452 #if DEBUG_BACKINGSTORE
453     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::startRenderTimer time=%f", WTF::currentTime());
454 #endif
455     m_renderTimer->startOneShot(s_renderTimerTimeout);
456 }
457
458 void BackingStorePrivate::stopRenderTimer()
459 {
460     if (!m_renderTimer->isActive())
461         return;
462
463     // Called when we render something to restart.
464 #if DEBUG_BACKINGSTORE
465     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::stopRenderTimer time=%f", WTF::currentTime());
466 #endif
467     m_renderTimer->stop();
468 }
469
470 void BackingStorePrivate::renderOnTimer(WebCore::Timer<BackingStorePrivate>*)
471 {
472     // This timer is a third method of starting a render operation that is a catch-all. If more
473     // than s_renderTimerTimeout elapses with no rendering taking place and render jobs in the queue, then
474     // renderOnTimer will be called which will actually render.
475     if (!shouldPerformRenderJobs())
476         return;
477
478 #if DEBUG_BACKINGSTORE
479     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::renderOnTimer time=%f", WTF::currentTime());
480 #endif
481     while (m_renderQueue->hasCurrentVisibleZoomJob() || m_renderQueue->hasCurrentVisibleScrollJob())
482         m_renderQueue->render(!m_suspendRegularRenderJobs);
483
484     if (shouldPerformRegularRenderJobs() && m_renderQueue->hasCurrentRegularRenderJob())
485         m_renderQueue->renderAllCurrentRegularRenderJobs();
486
487 #if USE(ACCELERATED_COMPOSITING)
488     drawLayersOnCommitIfNeeded();
489 #endif
490 }
491
492 void BackingStorePrivate::renderOnIdle()
493 {
494     ASSERT(shouldPerformRenderJobs());
495
496     // Let the render queue know that we entered a new event queue cycle
497     // so it can determine if it is under pressure.
498     m_renderQueue->eventQueueCycled();
499
500 #if DEBUG_BACKINGSTORE
501     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::renderOnIdle");
502 #endif
503
504     m_renderQueue->render(!m_suspendRegularRenderJobs);
505
506 #if USE(ACCELERATED_COMPOSITING)
507     drawLayersOnCommitIfNeeded();
508 #endif
509 }
510
511 bool BackingStorePrivate::willFireTimer()
512 {
513     // Let the render queue know that we entered a new event queue cycle
514     // so it can determine if it is under pressure.
515     m_renderQueue->eventQueueCycled();
516
517     if (!shouldPerformRegularRenderJobs() || !m_renderQueue->hasCurrentRegularRenderJob() || !m_renderQueue->currentRegularRenderJobBatchUnderPressure())
518         return true;
519
520 #if DEBUG_BACKINGSTORE
521     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::willFireTimer");
522 #endif
523
524     // We've detected that the regular render jobs are coming under pressure likely
525     // due to timers firing producing invalidation jobs and our efforts to break them
526     // up into bite size pieces has produced a situation where we can not complete
527     // a batch of them before receiving more that intersect them which causes us
528     // to start the batch over. To mitigate this we have to empty the current batch
529     // when this is detected.
530
531     // We still want to perform priority jobs first to avoid redundant paints.
532     while (m_renderQueue->hasCurrentVisibleZoomJob() || m_renderQueue->hasCurrentVisibleScrollJob())
533         m_renderQueue->render(!m_suspendRegularRenderJobs);
534
535     if (m_renderQueue->hasCurrentRegularRenderJob())
536         m_renderQueue->renderAllCurrentRegularRenderJobs();
537
538 #if USE(ACCELERATED_COMPOSITING)
539     drawLayersOnCommitIfNeeded();
540 #endif
541
542     // Let the caller yield and reschedule the timer.
543     return false;
544 }
545
546 Platform::IntRect BackingStorePrivate::expandedContentsRect() const
547 {
548     return Platform::IntRect(Platform::IntPoint(0, 0), expandedContentsSize());
549 }
550
551 Platform::IntRect BackingStorePrivate::visibleContentsRect() const
552 {
553     return intersection(m_client->transformedVisibleContentsRect(),
554                         Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedContentsSize()));
555 }
556
557 Platform::IntRect BackingStorePrivate::unclippedVisibleContentsRect() const
558 {
559     return m_client->transformedVisibleContentsRect();
560 }
561
562 bool BackingStorePrivate::shouldMoveLeft(const Platform::IntRect& backingStoreRect) const
563 {
564     return canMoveX(backingStoreRect)
565             && backingStoreRect.x() > visibleContentsRect().x()
566             && backingStoreRect.x() > expandedContentsRect().x();
567 }
568
569 bool BackingStorePrivate::shouldMoveRight(const Platform::IntRect& backingStoreRect) const
570 {
571     return canMoveX(backingStoreRect)
572             && backingStoreRect.right() < visibleContentsRect().right()
573             && backingStoreRect.right() < expandedContentsRect().right();
574 }
575
576 bool BackingStorePrivate::shouldMoveUp(const Platform::IntRect& backingStoreRect) const
577 {
578     return canMoveY(backingStoreRect)
579             && backingStoreRect.y() > visibleContentsRect().y()
580             && backingStoreRect.y() > expandedContentsRect().y();
581 }
582
583 bool BackingStorePrivate::shouldMoveDown(const Platform::IntRect& backingStoreRect) const
584 {
585     return canMoveY(backingStoreRect)
586             && backingStoreRect.bottom() < visibleContentsRect().bottom()
587             && backingStoreRect.bottom() < expandedContentsRect().bottom();
588 }
589
590 bool BackingStorePrivate::canMoveX(const Platform::IntRect& backingStoreRect) const
591 {
592     return backingStoreRect.width() > visibleContentsRect().width();
593 }
594
595 bool BackingStorePrivate::canMoveY(const Platform::IntRect& backingStoreRect) const
596 {
597     return backingStoreRect.height() > visibleContentsRect().height();
598 }
599
600 bool BackingStorePrivate::canMoveLeft(const Platform::IntRect& rect) const
601 {
602     Platform::IntRect backingStoreRect = rect;
603     Platform::IntRect visibleContentsRect = this->visibleContentsRect();
604     Platform::IntRect contentsRect = this->expandedContentsRect();
605     backingStoreRect.move(-tileWidth(), 0);
606     return backingStoreRect.right() >= visibleContentsRect.right()
607             && backingStoreRect.x() >= contentsRect.x();
608 }
609
610 bool BackingStorePrivate::canMoveRight(const Platform::IntRect& rect) const
611 {
612     Platform::IntRect backingStoreRect = rect;
613     Platform::IntRect visibleContentsRect = this->visibleContentsRect();
614     Platform::IntRect contentsRect = this->expandedContentsRect();
615     backingStoreRect.move(tileWidth(), 0);
616     return backingStoreRect.x() <= visibleContentsRect.x()
617             && (backingStoreRect.right() <= contentsRect.right()
618             || (backingStoreRect.right() - contentsRect.right()) < tileWidth());
619 }
620
621 bool BackingStorePrivate::canMoveUp(const Platform::IntRect& rect) const
622 {
623     Platform::IntRect backingStoreRect = rect;
624     Platform::IntRect visibleContentsRect = this->visibleContentsRect();
625     Platform::IntRect contentsRect = this->expandedContentsRect();
626     backingStoreRect.move(0, -tileHeight());
627     return backingStoreRect.bottom() >= visibleContentsRect.bottom()
628             && backingStoreRect.y() >= contentsRect.y();
629 }
630
631 bool BackingStorePrivate::canMoveDown(const Platform::IntRect& rect) const
632 {
633     Platform::IntRect backingStoreRect = rect;
634     Platform::IntRect visibleContentsRect = this->visibleContentsRect();
635     Platform::IntRect contentsRect = this->expandedContentsRect();
636     backingStoreRect.move(0, tileHeight());
637     return backingStoreRect.y() <= visibleContentsRect.y()
638             && (backingStoreRect.bottom() <= contentsRect.bottom()
639             || (backingStoreRect.bottom() - contentsRect.bottom()) < tileHeight());
640 }
641
642 Platform::IntRect BackingStorePrivate::backingStoreRectForScroll(int deltaX, int deltaY, const Platform::IntRect& rect) const
643 {
644     // The current rect.
645     Platform::IntRect backingStoreRect = rect;
646
647     // This method uses the delta values to describe the backingstore rect
648     // given the current scroll direction and the viewport position. However,
649     // this method can be called with no deltas whatsoever for instance when
650     // the contents size changes or the orientation changes. In this case, we
651     // want to use the previous scroll direction to describe the backingstore
652     // rect. This will result in less checkerboard.
653     if (!deltaX && !deltaY) {
654         deltaX = m_previousDelta.width();
655         deltaY = m_previousDelta.height();
656     }
657     m_previousDelta = Platform::IntSize(deltaX, deltaY);
658
659     // Return to origin if need be.
660     if (!canMoveX(backingStoreRect) && backingStoreRect.x())
661         backingStoreRect.setX(0);
662
663     if (!canMoveY(backingStoreRect) && backingStoreRect.y())
664         backingStoreRect.setY(0);
665
666     // Move the rect left.
667     while (shouldMoveLeft(backingStoreRect) || (deltaX > 0 && canMoveLeft(backingStoreRect)))
668         backingStoreRect.move(-tileWidth(), 0);
669
670     // Move the rect right.
671     while (shouldMoveRight(backingStoreRect) || (deltaX < 0 && canMoveRight(backingStoreRect)))
672         backingStoreRect.move(tileWidth(), 0);
673
674     // Move the rect up.
675     while (shouldMoveUp(backingStoreRect) || (deltaY > 0 && canMoveUp(backingStoreRect)))
676         backingStoreRect.move(0, -tileHeight());
677
678     // Move the rect down.
679     while (shouldMoveDown(backingStoreRect) || (deltaY < 0 && canMoveDown(backingStoreRect)))
680         backingStoreRect.move(0, tileHeight());
681
682     return backingStoreRect;
683 }
684
685 void BackingStorePrivate::setBackingStoreRect(const Platform::IntRect& backingStoreRect)
686 {
687     if (!m_webPage->isVisible())
688         return;
689
690     if (!isActive()) {
691         m_webPage->d->setShouldResetTilesWhenShown(true);
692         return;
693     }
694
695     Platform::IntRect currentBackingStoreRect = frontState()->backingStoreRect();
696
697     if (backingStoreRect == currentBackingStoreRect)
698         return;
699
700 #if DEBUG_TILEMATRIX
701     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::setBackingStoreRect changed from (%d,%d %dx%d) to (%d,%d %dx%d)",
702                            currentBackingStoreRect.x(),
703                            currentBackingStoreRect.y(),
704                            currentBackingStoreRect.width(),
705                            currentBackingStoreRect.height(),
706                            backingStoreRect.x(),
707                            backingStoreRect.y(),
708                            backingStoreRect.width(),
709                            backingStoreRect.height());
710 #endif
711
712     BackingStoreGeometry* currentState = frontState();
713     TileMap currentMap = currentState->tileMap();
714
715     TileIndexList indexesToFill = indexesForBackingStoreRect(backingStoreRect);
716
717     ASSERT(static_cast<int>(indexesToFill.size()) == currentMap.size());
718
719     TileMap newTileMap;
720     TileMap leftOverTiles;
721
722     // Iterate through our current tile map and add tiles that are rendered with
723     // our new backing store rect.
724     TileMap::const_iterator tileMapEnd = currentMap.end();
725     for (TileMap::const_iterator it = currentMap.begin(); it != tileMapEnd; ++it) {
726         TileIndex oldIndex = it->first;
727         BackingStoreTile* tile = it->second;
728
729         // Reset the old index.
730         resetTile(oldIndex, tile, false /*resetBackground*/);
731
732         // Origin of last committed render for tile in transformed content coordinates.
733         Platform::IntPoint origin = originOfLastRenderForTile(oldIndex, tile, currentBackingStoreRect);
734
735         // If the new backing store rect contains this origin, then insert the tile there
736         // and mark it as no longer shifted. Note: Platform::IntRect::contains checks for a 1x1 rect
737         // below and to the right of the origin so it is correct usage here.
738         if (backingStoreRect.contains(origin)) {
739             TileIndex newIndex = indexOfTile(origin, backingStoreRect);
740             Platform::IntRect rect(origin, tileSize());
741             if (m_renderQueue->regularRenderJobsPreviouslyAttemptedButNotRendered(rect)) {
742                 // If the render queue previously tried to render this tile, but the
743                 // backingstore wasn't in the correct place or the tile wasn't visible
744                 // at the time then we can't simply restore the tile since the content
745                 // is now invalid as far as WebKit is concerned. Instead, we clear
746                 // the tile here of the region and then put the tile in the render
747                 // queue again.
748
749                 // Intersect the tile with the not rendered region to get the areas
750                 // of the tile that we need to clear.
751                 Platform::IntRectRegion tileNotRenderedRegion = Platform::IntRectRegion::intersectRegions(m_renderQueue->regularRenderJobsNotRenderedRegion(), rect);
752                 clearAndUpdateTileOfNotRenderedRegion(newIndex, tile, tileNotRenderedRegion, backingStoreRect);
753 #if DEBUG_BACKINGSTORE
754                 Platform::IntRect extents = tileNotRenderedRegion.extents();
755                 BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::setBackingStoreRect did clear tile %d,%d %dx%d",
756                                        extents.x(), extents.y(), extents.width(), extents.height());
757 #endif
758             } else {
759                 // Mark as needing update.
760                 if (!tile->frontBuffer()->isRendered()
761                     && !isCurrentVisibleJob(newIndex, tile, backingStoreRect))
762                     updateTile(origin, false /*immediate*/);
763             }
764
765             // Do some bookkeeping with shifting tiles...
766             tile->clearShift();
767             tile->setCommitted(true);
768
769             size_t i = indexesToFill.find(newIndex);
770             ASSERT(i != WTF::notFound);
771             indexesToFill.remove(i);
772             newTileMap.add(newIndex, tile);
773         } else {
774             // Store this tile and index so we can add it to the remaining left over spots...
775             leftOverTiles.add(oldIndex, tile);
776         }
777     }
778
779     ASSERT(static_cast<int>(indexesToFill.size()) == leftOverTiles.size());
780     size_t i = 0;
781     TileMap::const_iterator leftOverEnd = leftOverTiles.end();
782     for (TileMap::const_iterator it = leftOverTiles.begin(); it != leftOverEnd; ++it) {
783         TileIndex oldIndex = it->first;
784         BackingStoreTile* tile = it->second;
785         if (i >= indexesToFill.size()) {
786             ASSERT_NOT_REACHED();
787             break;
788         }
789
790         TileIndex newIndex = indexesToFill.at(i);
791
792         // Origin of last committed render for tile in transformed content coordinates.
793         Platform::IntPoint originOfOld = originOfLastRenderForTile(oldIndex, tile, currentBackingStoreRect);
794         // Origin of the new index for the new backing store rect.
795         Platform::IntPoint originOfNew = originOfTile(newIndex, backingStoreRect);
796
797         // Mark as needing update.
798         updateTile(originOfNew, false /*immediate*/);
799
800         tile->clearShift();
801         tile->setCommitted(false);
802         tile->setHorizontalShift((originOfOld.x() - originOfNew.x()) / tileWidth());
803         tile->setVerticalShift((originOfOld.y() - originOfNew.y()) / tileHeight());
804
805         newTileMap.add(newIndex, tile);
806
807         ++i;
808     }
809
810     // Checks to make sure we haven't lost any tiles.
811     ASSERT(currentMap.size() == newTileMap.size());
812
813     backState()->setNumberOfTilesWide(backingStoreRect.width() / tileWidth());
814     backState()->setNumberOfTilesHigh(backingStoreRect.height() / tileHeight());
815     backState()->setBackingStoreOffset(backingStoreRect.location());
816     backState()->setTileMap(newTileMap);
817
818     swapState();
819 }
820
821 BackingStorePrivate::TileIndexList BackingStorePrivate::indexesForBackingStoreRect(const Platform::IntRect& backingStoreRect) const
822 {
823     TileIndexList indexes;
824     int numberOfTilesWide = backingStoreRect.width() / tileWidth();
825     int numberOfTilesHigh = backingStoreRect.height() / tileHeight();
826     for (int y = 0; y < numberOfTilesHigh; ++y) {
827         for (int x = 0; x < numberOfTilesWide; ++x) {
828             TileIndex index(x, y);
829             indexes.append(index);
830         }
831     }
832     return indexes;
833 }
834
835 Platform::IntPoint BackingStorePrivate::originOfLastRenderForTile(const TileIndex& index,
836                                                                  BackingStoreTile* tile,
837                                                                  const Platform::IntRect& backingStoreRect) const
838 {
839     return originOfTile(indexOfLastRenderForTile(index, tile), backingStoreRect);
840 }
841
842 TileIndex BackingStorePrivate::indexOfLastRenderForTile(const TileIndex& index, BackingStoreTile* tile) const
843 {
844     return TileIndex(index.i() + tile->horizontalShift(), index.j() + tile->verticalShift());
845 }
846
847 TileIndex BackingStorePrivate::indexOfTile(const Platform::IntPoint& origin,
848                                            const Platform::IntRect& backingStoreRect) const
849 {
850     int offsetX = origin.x() - backingStoreRect.x();
851     int offsetY = origin.y() - backingStoreRect.y();
852     if (offsetX)
853         offsetX = offsetX / tileWidth();
854     if (offsetY)
855         offsetY = offsetY / tileHeight();
856     return TileIndex(offsetX, offsetY);
857 }
858
859 void BackingStorePrivate::clearAndUpdateTileOfNotRenderedRegion(const TileIndex& index, BackingStoreTile* tile,
860                                                                 const Platform::IntRectRegion& tileNotRenderedRegion,
861                                                                 const Platform::IntRect& backingStoreRect,
862                                                                 bool update)
863 {
864     // Intersect the tile with the not rendered region to get the areas
865     // of the tile that we need to clear.
866     IntRectList tileNotRenderedRegionRects = tileNotRenderedRegion.rects();
867     for (size_t i = 0; i < tileNotRenderedRegionRects.size(); ++i) {
868         Platform::IntRect tileNotRenderedRegionRect = tileNotRenderedRegionRects.at(i);
869         // Clear the render queue of this rect.
870         m_renderQueue->clear(tileNotRenderedRegionRect, true /*clearRegularRenderJobs*/);
871
872         if (update) {
873             // Add it again as a regular render job.
874             m_renderQueue->addToQueue(RenderQueue::RegularRender, tileNotRenderedRegionRect);
875         }
876
877         // Find the origin of this tile.
878         Platform::IntPoint origin = originOfTile(index, backingStoreRect);
879
880         // Map to tile coordinates.
881         tileNotRenderedRegionRect.move(-origin.x(), -origin.y());
882
883         // Clear the tile of this region.
884         tile->frontBuffer()->clearRenderedRegion(tileNotRenderedRegionRect);
885         tile->backBuffer()->clearRenderedRegion(tileNotRenderedRegionRect);
886     }
887 }
888
889 bool BackingStorePrivate::isCurrentVisibleJob(const TileIndex& index, BackingStoreTile* tile, const Platform::IntRect& backingStoreRect) const
890 {
891     // First check if the whole rect is in the queue.
892     Platform::IntRect wholeRect = Platform::IntRect(originOfTile(index, backingStoreRect), tileSize());
893     if (m_renderQueue->isCurrentVisibleScrollJob(wholeRect) || m_renderQueue->isCurrentVisibleScrollJobCompleted(wholeRect))
894         return true;
895
896     // Second check if the individual parts of the non-rendered region are in the regular queue.
897     bool isCurrent = true; // It is true until it isn't :)
898
899     IntRectList tileNotRenderedRegionRects = tile->frontBuffer()->notRenderedRegion().rects();
900     for (size_t i = 0; i < tileNotRenderedRegionRects.size(); ++i) {
901         Platform::IntRect tileNotRenderedRegionRect = tileNotRenderedRegionRects.at(i);
902         Platform::IntPoint origin = originOfTile(index, backingStoreRect);
903
904         // Map to transformed contents coordinates.
905         tileNotRenderedRegionRect.move(origin.x(), origin.y());
906
907         isCurrent = m_renderQueue->isCurrentRegularRenderJob(tileNotRenderedRegionRect) ? isCurrent : false;
908     }
909
910     return isCurrent;
911 }
912
913 void BackingStorePrivate::scrollBackingStore(int deltaX, int deltaY)
914 {
915     if (!m_webPage->isVisible())
916         return;
917
918     if (!isActive()) {
919         m_webPage->d->setShouldResetTilesWhenShown(true);
920         return;
921     }
922
923     // Calculate our new preferred matrix dimension.
924     if (deltaX || deltaY)
925         m_preferredTileMatrixDimension = abs(deltaX) > abs(deltaY) ? Horizontal : Vertical;
926
927     // Calculate our preferred matrix geometry.
928     Divisor divisor = bestDivisor(expandedContentsSize(),
929                                   tileWidth(), tileHeight(),
930                                   minimumNumberOfTilesWide(), minimumNumberOfTilesHigh(),
931                                   m_preferredTileMatrixDimension);
932
933 #if DEBUG_TILEMATRIX
934     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::scrollBackingStore divisor %dx%d",
935                            divisor.first,
936                            divisor.second);
937 #endif
938
939     // Initialize a rect with that new geometry.
940     Platform::IntRect backingStoreRect(0, 0, divisor.first * tileWidth(), divisor.second * tileHeight());
941
942     // Scroll that rect so that it fits our contents and viewport and scroll delta.
943     backingStoreRect = backingStoreRectForScroll(deltaX, deltaY, backingStoreRect);
944
945     ASSERT(!backingStoreRect.isEmpty());
946
947     setBackingStoreRect(backingStoreRect);
948 }
949
950 bool BackingStorePrivate::renderDirectToWindow(const Platform::IntRect& rect)
951 {
952     requestLayoutIfNeeded();
953
954     Platform::IntRect dirtyRect = rect;
955     dirtyRect.intersect(unclippedVisibleContentsRect());
956
957     if (dirtyRect.isEmpty())
958         return false;
959
960     Platform::IntRect screenRect = m_client->mapFromTransformedContentsToTransformedViewport(dirtyRect);
961     windowFrontBufferState()->clearBlittedRegion(screenRect);
962
963     paintDefaultBackground(dirtyRect, TransformationMatrix(), true /*flush*/);
964
965     const Platform::IntPoint origin = unclippedVisibleContentsRect().location();
966     // We don't need a buffer since we're direct rendering to window.
967     renderContents(0, origin, dirtyRect);
968     windowBackBufferState()->addBlittedRegion(screenRect);
969
970 #if USE(ACCELERATED_COMPOSITING)
971     m_isDirectRenderingAnimationMessageScheduled = false;
972
973     if (m_webPage->d->isAcceleratedCompositingActive()) {
974         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
975             BlackBerry::Platform::createMethodCallMessage(
976                 &BackingStorePrivate::drawAndBlendLayersForDirectRendering,
977                 this, dirtyRect));
978     }
979 #endif
980
981     invalidateWindow(screenRect);
982     return true;
983 }
984
985 bool BackingStorePrivate::render(const Platform::IntRect& rect)
986 {
987     if (!m_webPage->isVisible())
988         return false;
989
990     requestLayoutIfNeeded();
991
992     if (shouldDirectRenderingToWindow())
993         return renderDirectToWindow(rect);
994
995     TileRectList tileRectList = mapFromTransformedContentsToTiles(rect);
996     if (tileRectList.isEmpty())
997         return false;
998
999 #if DEBUG_BACKINGSTORE
1000     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
1001                            "BackingStorePrivate::render rect=(%d,%d %dx%d), m_suspendBackingStoreUpdates = %s",
1002                            rect.x(), rect.y(), rect.width(), rect.height(),
1003                            m_suspendBackingStoreUpdates ? "true" : "false");
1004 #endif
1005
1006     bool blittingDirectlyToCompositingWindow = isOpenGLCompositing();
1007
1008     BackingStoreGeometry* currentState = frontState();
1009     TileMap currentMap = currentState->tileMap();
1010
1011     Platform::IntRect dirtyContentsRect;
1012
1013     for (size_t i = 0; i < tileRectList.size(); ++i) {
1014         TileRect tileRect = tileRectList[i];
1015         TileIndex index = tileRect.first;
1016         Platform::IntRect dirtyTileRect = tileRect.second;
1017         BackingStoreTile* tile = currentMap.get(index);
1018
1019         // This dirty tile rect is in tile coordinates, but it needs to be in
1020         // transformed contents coordinates.
1021         Platform::IntRect dirtyRect = mapFromTilesToTransformedContents(tileRect);
1022
1023         // If we're not yet committed, then commit now by clearing the rendered region
1024         // and setting the committed flag as well as clearing the shift.
1025         if (!tile->isCommitted()) {
1026             tile->setCommitted(true);
1027             tile->frontBuffer()->clearRenderedRegion();
1028             tile->backBuffer()->clearRenderedRegion();
1029             tile->clearShift();
1030         }
1031
1032         // If the tile has been created, but this is the first time we are painting on it
1033         // then it hasn't been given a default background yet so that we can save time during
1034         // startup. That's why we are doing it here instead...
1035         if (!tile->backgroundPainted())
1036             tile->paintBackground();
1037
1038         // Paint default background if contents rect is empty.
1039         if (!expandedContentsRect().isEmpty()) {
1040             // Otherwise we should clip the contents size and render the content.
1041             dirtyRect.intersect(expandedContentsRect());
1042
1043             dirtyTileRect.intersect(tileContentsRect(index, expandedContentsRect(), currentState));
1044
1045             // We probably have extra tiles since the contents size is so small.
1046             // Save some cycles here...
1047             if (dirtyRect.isEmpty())
1048                 continue;
1049         }
1050
1051         copyPreviousContentsToBackSurfaceOfTile(dirtyTileRect, tile);
1052
1053         BlackBerry::Platform::Graphics::Buffer* nativeBuffer
1054             = tile->backBuffer()->nativeBuffer();
1055
1056         if (blittingDirectlyToCompositingWindow) {
1057             pthread_mutex_lock(&m_blitGenerationLock);
1058             while (m_blitGeneration == tile->backBuffer()->blitGeneration()) {
1059                 int err = pthread_cond_timedwait(&m_blitGenerationCond, &m_blitGenerationLock, &m_currentBlitEnd);
1060                 if (err == ETIMEDOUT) {
1061                     ++m_blitGeneration;
1062                     break;
1063                 }
1064                 if (err) {
1065                     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
1066                                               "cond_timedwait failed (%s)", strerror(err));
1067                     break;
1068                 }
1069             }
1070             pthread_mutex_unlock(&m_blitGenerationLock);
1071         }
1072
1073         // FIXME: modify render to take a Vector<IntRect> parameter so we're not recreating
1074         // GraphicsContext on the stack each time.
1075         renderContents(nativeBuffer, originOfTile(index), dirtyRect);
1076
1077         // Add the newly rendered region to the tile so it can keep track for blits.
1078         tile->backBuffer()->addRenderedRegion(dirtyTileRect);
1079
1080         // Check if the contents for this tile's backbuffer are valid when
1081         // compared to the front buffer.
1082         bool backBufferIsValid = tile->backBuffer()->isRendered(tile->frontBuffer()->renderedRegion());
1083
1084         // Our current design demands that the backbuffer is valid after any
1085         // rendering operation so assert that here. If we hit this assert we
1086         // know that we're doing something bad that will result in artifacts.
1087         ASSERT(backBufferIsValid);
1088
1089         // We will need a swap here because of the shared back buffer.
1090         if (backBufferIsValid) {
1091             tile->swapBuffers();
1092             BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
1093             tile->backBuffer()->clearRenderedRegion();
1094         }
1095
1096         dirtyContentsRect = Platform::unionOfRects(dirtyContentsRect, dirtyRect);
1097     }
1098
1099     return true;
1100 }
1101
1102 void BackingStorePrivate::requestLayoutIfNeeded() const
1103 {
1104     m_webPage->d->requestLayoutIfNeeded();
1105 }
1106
1107 bool BackingStorePrivate::renderVisibleContents()
1108 {
1109     Platform::IntRect renderRect = shouldDirectRenderingToWindow() ? visibleContentsRect() : visibleTilesRect();
1110     if (render(renderRect)) {
1111         m_renderQueue->clear(renderRect, true /*clearRegularRenderJobs*/);
1112         return true;
1113     }
1114     return false;
1115 }
1116
1117 bool BackingStorePrivate::renderBackingStore()
1118 {
1119     return render(frontState()->backingStoreRect());
1120 }
1121
1122 void BackingStorePrivate::blitVisibleContents(bool force)
1123 {
1124     // Blitting must never happen for direct rendering case.
1125     ASSERT(!shouldDirectRenderingToWindow());
1126     if (shouldDirectRenderingToWindow())
1127         return;
1128
1129     if (m_suspendScreenUpdates) {
1130         // Avoid client going into busy loop while updates suspended.
1131         if (force)
1132             m_hasBlitJobs = false;
1133         return;
1134     }
1135
1136     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
1137 #if USE(ACCELERATED_COMPOSITING)
1138         // The blit will call drawSubLayers if necessary
1139         m_needsDrawLayersOnCommit = false;
1140 #endif
1141
1142         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
1143             BlackBerry::Platform::createMethodCallMessage(
1144                 &BackingStorePrivate::blitVisibleContents, this, force));
1145         return;
1146     }
1147
1148     blitContents(m_webPage->client()->userInterfaceBlittedDestinationRect(),
1149                  m_webPage->client()->userInterfaceBlittedVisibleContentsRect(),
1150                  force);
1151 }
1152
1153 void BackingStorePrivate::copyPreviousContentsToBackSurfaceOfWindow()
1154 {
1155     Platform::IntRectRegion previousContentsRegion
1156         = Platform::IntRectRegion::subtractRegions(windowFrontBufferState()->blittedRegion(), windowBackBufferState()->blittedRegion());
1157
1158     if (previousContentsRegion.isEmpty())
1159         return;
1160
1161     if (Window* window = m_webPage->client()->window())
1162         window->copyFromFrontToBack(previousContentsRegion);
1163     windowBackBufferState()->addBlittedRegion(previousContentsRegion);
1164 }
1165
1166 void BackingStorePrivate::copyPreviousContentsToBackSurfaceOfTile(const Platform::IntRect& rect,
1167                                                                   BackingStoreTile* tile)
1168 {
1169     Platform::IntRectRegion previousContentsRegion
1170         = Platform::IntRectRegion::subtractRegions(tile->frontBuffer()->renderedRegion(), rect);
1171
1172     IntRectList previousContentsRects = previousContentsRegion.rects();
1173     for (size_t i = 0; i < previousContentsRects.size(); ++i) {
1174         Platform::IntRect previousContentsRect = previousContentsRects.at(i);
1175         tile->backBuffer()->addRenderedRegion(previousContentsRect);
1176
1177         BlackBerry::Platform::Graphics::blitToBuffer(
1178             tile->backBuffer()->nativeBuffer(), previousContentsRect,
1179             tile->frontBuffer()->nativeBuffer(), previousContentsRect);
1180     }
1181 }
1182
1183 void BackingStorePrivate::paintDefaultBackground(const Platform::IntRect& contents,
1184                                                  const WebCore::TransformationMatrix& transformation,
1185                                                  bool flush)
1186 {
1187     const Platform::IntRect contentsRect = Platform::IntRect(Platform::IntPoint(0, 0), m_webPage->d->transformedContentsSize());
1188     Platform::IntPoint origin = contents.location();
1189     Platform::IntRect contentsClipped = contents;
1190
1191     // We have to paint the default background in the case of overzoom and
1192     // make sure it is invalidated.
1193     Color color(m_webPage->settings()->overZoomColor());
1194
1195     Platform::IntRectRegion overScrollRegion
1196             = Platform::IntRectRegion::subtractRegions(Platform::IntRect(contentsClipped), contentsRect);
1197
1198     IntRectList overScrollRects = overScrollRegion.rects();
1199     for (size_t i = 0; i < overScrollRects.size(); ++i) {
1200         Platform::IntRect overScrollRect = overScrollRects.at(i);
1201         overScrollRect.move(-origin.x(), -origin.y());
1202         overScrollRect = transformation.mapRect(overScrollRect);
1203
1204         if (!transformation.isIdentity()) {
1205             // Because of rounding it is possible that overScrollRect could be off-by-one larger
1206             // than the surface size of the window. We prevent this here, by clamping
1207             // it to ensure that can't happen.
1208             overScrollRect.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
1209         }
1210
1211         clearWindow(overScrollRect, color.red(), color.green(), color.blue(), color.alpha());
1212     }
1213 }
1214
1215 void BackingStorePrivate::blitContents(const Platform::IntRect& dstRect,
1216                                        const Platform::IntRect& srcRect,
1217                                        bool force)
1218 {
1219     // Blitting must never happen for direct rendering case.
1220     // Use invalidateWindow() instead.
1221     ASSERT(!shouldDirectRenderingToWindow());
1222     if (shouldDirectRenderingToWindow())
1223         return;
1224
1225     if (!m_webPage->isVisible() || m_suspendScreenUpdates || !isActive()) {
1226         // Avoid client going into busy loop while blit is impossible.
1227         if (force)
1228             m_hasBlitJobs = false;
1229         return;
1230     }
1231
1232     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
1233 #if USE(ACCELERATED_COMPOSITING)
1234         // The blit will call drawSubLayers if necessary
1235         m_needsDrawLayersOnCommit = false;
1236 #endif
1237
1238         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
1239             BlackBerry::Platform::createMethodCallMessage(
1240                 &BackingStorePrivate::blitContents, this, dstRect, srcRect, force));
1241         return;
1242     }
1243
1244     if (m_defersBlit && !force) {
1245 #if USE(ACCELERATED_COMPOSITING)
1246         // If there's a WebPageCompositorClient, let it schedule the blit.
1247         if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor()) {
1248             if (WebPageCompositorClient* client = compositor->client()) {
1249                 client->invalidate(compositor->animationFrameTimestamp());
1250                 return;
1251             }
1252         }
1253 #endif
1254
1255         m_hasBlitJobs = true;
1256         return;
1257     }
1258
1259     m_hasBlitJobs = false;
1260
1261     BackingStoreGeometry* currentState = frontState();
1262     const Platform::IntRect contentsRect = Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedContentsSize());
1263
1264 #if DEBUG_VISUALIZE
1265     // Substitute a debugRect that consists of the union of the backingstore rect
1266     // and the ui thread viewport rect instead of the normal source rect so we
1267     // can visualize the entire backingstore and what it is doing when we
1268     // scroll and zoom!
1269     // FIXME: This should not explicitely depend on WebCore::.
1270     WebCore::IntRect debugRect = currentState->backingStoreRect();
1271     debugRect.unite(m_webPage->client()->userInterfaceBlittedVisibleContentsRect());
1272     if (debugRect.width() < debugRect.height())
1273         debugRect.setWidth(ceil(double(srcRect.width()) * (double(debugRect.height()) / srcRect.height())));
1274     if (debugRect.height() < debugRect.width())
1275         debugRect.setHeight(ceil(double(srcRect.height()) * (double(debugRect.width()) / srcRect.width())));
1276     Platform::IntRect contents = debugRect;
1277 #else
1278     Platform::IntRect contents = srcRect;
1279 #endif
1280
1281     // FIXME: This should not explicitely depend on WebCore::.
1282     TransformationMatrix transformation;
1283     if (!contents.isEmpty())
1284         transformation = TransformationMatrix::rectToRect(FloatRect(FloatPoint(0.0, 0.0), WebCore::IntSize(contents.size())), WebCore::IntRect(dstRect));
1285
1286     bool blittingDirectlyToCompositingWindow = isOpenGLCompositing();
1287 #if USE(ACCELERATED_COMPOSITING)
1288     BackingStoreCompositingSurface* compositingSurface =
1289         SurfacePool::globalSurfacePool()->compositingSurface();
1290
1291     if (!blittingDirectlyToCompositingWindow)
1292         drawSubLayers();
1293 #endif
1294
1295 #if DEBUG_BACKINGSTORE
1296     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
1297                            "BackingStorePrivate::blitContents dstRect=(%d,%d %dx%d) srcRect=(%d,%d %dx%d)",
1298                            dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(),
1299                            srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
1300 #endif
1301
1302     Platform::IntPoint origin = contents.location();
1303     Platform::IntRect contentsClipped = contents;
1304
1305     paintDefaultBackground(contents, transformation, false /*flush*/);
1306
1307     TileMap currentMap = currentState->tileMap();
1308
1309 #if DEBUG_CHECKERBOARD
1310     bool blitCheckered = false;
1311 #endif
1312
1313     // Don't clip to contents if it is empty so we can still paint default background.
1314     if (!contentsRect.isEmpty()) {
1315         contentsClipped.intersect(contentsRect);
1316         if (contentsClipped.isEmpty()) {
1317             invalidateWindow(dstRect);
1318             return;
1319         }
1320
1321         Platform::IntRectRegion contentsRegion = contentsClipped;
1322         Platform::IntRectRegion backingStoreRegion = currentState->backingStoreRect();
1323         Platform::IntRectRegion checkeredRegion
1324             = Platform::IntRectRegion::subtractRegions(contentsRegion, backingStoreRegion);
1325
1326         // Blit checkered to those parts that are not covered by the backingStoreRect.
1327         IntRectList checkeredRects = checkeredRegion.rects();
1328         for (size_t i = 0; i < checkeredRects.size(); ++i) {
1329             Platform::IntRect dstRect = transformation.mapRect(Platform::IntRect(
1330                 Platform::IntPoint(checkeredRects.at(i).x() - origin.x(), checkeredRects.at(i).y() - origin.y()),
1331                                    checkeredRects.at(i).size()));
1332 #if DEBUG_CHECKERBOARD
1333             blitCheckered = true;
1334 #endif
1335             checkerWindow(dstRect, checkeredRects.at(i).location(), transformation.a());
1336         }
1337     }
1338
1339     Vector<TileBuffer*> blittedTiles;
1340
1341     // Get the list of tile rects that makeup the content.
1342     TileRectList tileRectList = mapFromTransformedContentsToTiles(contentsClipped, currentState);
1343     for (size_t i = 0; i < tileRectList.size(); ++i) {
1344         TileRect tileRect = tileRectList[i];
1345         TileIndex index = tileRect.first;
1346         Platform::IntRect dirtyTileRect = tileRect.second;
1347         BackingStoreTile* tile = currentMap.get(index);
1348         TileBuffer* tileBuffer = tile->frontBuffer();
1349
1350         // This dirty rect is in tile coordinates, but it needs to be in
1351         // transformed contents coordinates.
1352         Platform::IntRect dirtyRect
1353             = mapFromTilesToTransformedContents(tileRect, currentState->backingStoreRect());
1354
1355         // Don't clip to contents if it is empty so we can still paint default background.
1356         if (!contentsRect.isEmpty()) {
1357             // Otherwise we should clip the contents size and blit.
1358             dirtyRect.intersect(contentsRect);
1359
1360             // We probably have extra tiles since the contents size is so small.
1361             // Save some cycles here...
1362             if (dirtyRect.isEmpty())
1363                 continue;
1364         }
1365
1366         // Now, this dirty rect is in transformed coordinates relative to the
1367         // transformed contents, but ultimately it needs to be transformed
1368         // coordinates relative to the viewport.
1369         dirtyRect.move(-origin.x(), -origin.y());
1370
1371         // Save some cycles here...
1372         if (dirtyRect.isEmpty() || dirtyTileRect.isEmpty())
1373             continue;
1374
1375         TileRect wholeTileRect;
1376         wholeTileRect.first = index;
1377         wholeTileRect.second = this->tileRect();
1378
1379         bool committed = tile->isCommitted();
1380         bool rendered = tileBuffer->isRendered(dirtyTileRect);
1381         bool paintCheckered = !committed || !rendered;
1382
1383         if (paintCheckered) {
1384             Platform::IntRect dirtyRectT = transformation.mapRect(dirtyRect);
1385
1386             if (!transformation.isIdentity()) {
1387                 // Because of rounding it is possible that dirtyRect could be off-by-one larger
1388                 // than the surface size of the dst buffer. We prevent this here, by clamping
1389                 // it to ensure that can't happen.
1390                 dirtyRectT.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
1391             }
1392             const Platform::IntPoint contentsOrigin(dirtyRect.x() + origin.x(), dirtyRect.y() + origin.y());
1393 #if DEBUG_CHECKERBOARD
1394             blitCheckered = true;
1395 #endif
1396             checkerWindow(dirtyRectT, contentsOrigin, transformation.a());
1397         }
1398
1399         // Blit the visible buffer here if we have visible zoom jobs.
1400         if (m_renderQueue->hasCurrentVisibleZoomJob()) {
1401
1402             // Needs to be in same coordinate system as dirtyRect.
1403             Platform::IntRect visibleTileBufferRect = m_visibleTileBufferRect;
1404             visibleTileBufferRect.move(-origin.x(), -origin.y());
1405
1406             // Clip to the visibleTileBufferRect.
1407             dirtyRect.intersect(visibleTileBufferRect);
1408
1409             // Clip to the dirtyRect.
1410             visibleTileBufferRect.intersect(dirtyRect);
1411
1412             if (!dirtyRect.isEmpty() && !visibleTileBufferRect.isEmpty()) {
1413                 BackingStoreTile* visibleTileBuffer
1414                     = SurfacePool::globalSurfacePool()->visibleTileBuffer();
1415                 ASSERT(visibleTileBuffer->size() == visibleContentsRect().size());
1416
1417                 // The offset of the current viewport with the visble tile buffer.
1418                 Platform::IntPoint difference = origin - m_visibleTileBufferRect.location();
1419                 Platform::IntSize offset = Platform::IntSize(difference.x(), difference.y());
1420
1421                 // Map to the visibleTileBuffer coordinates.
1422                 Platform::IntRect dirtyTileRect = visibleTileBufferRect;
1423                 dirtyTileRect.move(offset.width(), offset.height());
1424
1425                 Platform::IntRect dirtyRectT = transformation.mapRect(dirtyRect);
1426
1427                 if (!transformation.isIdentity()) {
1428                     // Because of rounding it is possible that dirtyRect could be off-by-one larger
1429                     // than the surface size of the dst buffer. We prevent this here, by clamping
1430                     // it to ensure that can't happen.
1431                     dirtyRectT.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
1432                 }
1433
1434                 blitToWindow(dirtyRectT,
1435                              visibleTileBuffer->frontBuffer()->nativeBuffer(),
1436                              dirtyTileRect,
1437                              false /*blend*/, 255);
1438             }
1439         } else if (committed) {
1440             // Intersect the rendered region.
1441             Platform::IntRectRegion renderedRegion = tileBuffer->renderedRegion();
1442             IntRectList dirtyRenderedRects = renderedRegion.rects();
1443             for (size_t i = 0; i < dirtyRenderedRects.size(); ++i) {
1444                 TileRect tileRect;
1445                 tileRect.first = index;
1446                 tileRect.second = intersection(dirtyTileRect, dirtyRenderedRects.at(i));
1447                 if (tileRect.second.isEmpty())
1448                     continue;
1449                 // Blit the rendered parts.
1450                 blitTileRect(tileBuffer, tileRect, origin, transformation, currentState);
1451             }
1452             blittedTiles.append(tileBuffer);
1453         }
1454     }
1455
1456 #if USE(ACCELERATED_COMPOSITING)
1457     if (blittingDirectlyToCompositingWindow) {
1458         WebCore::FloatRect contentsRect = m_webPage->d->mapFromTransformedFloatRect(
1459             WebCore::FloatRect(WebCore::IntRect(contents)));
1460         if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
1461             compositor->drawLayers(dstRect, contentsRect);
1462     } else if (compositingSurface)
1463         blendCompositingSurface(dstRect);
1464
1465 #endif
1466
1467 #if ENABLE_SCROLLBARS
1468     if (isScrollingOrZooming() && m_client->isMainFrame()) {
1469         if (m_client->scrollsHorizontally())
1470             blitHorizontalScrollbar(origin);
1471         if (m_client->scrollsVertically())
1472             blitVerticalScrollbar(origin);
1473     }
1474 #endif
1475
1476 #if DEBUG_VISUALIZE
1477     // FIXME: This should not explicitely depend on WebCore::.
1478     BlackBerry::Platform::Graphics::Buffer* windowBuffer = buffer();
1479     BlackBerry::Platform::Graphics::Drawable* bufferDrawable =
1480         BlackBerry::Platform::Graphics::lockBufferDrawable(windowBuffer);
1481     PlatformGraphicsContext* bufferPlatformGraphicsContext =
1482         SurfacePool::globalSurfacePool()->createPlatformGraphicsContext(bufferDrawable);
1483     GraphicsContext graphicsContext(bufferPlatformGraphicsContext);
1484     FloatRect wkViewport = FloatRect(visibleContentsRect());
1485     FloatRect uiViewport = FloatRect(m_webPage->client()->userInterfaceBlittedVisibleContentsRect());
1486     wkViewport.move(-contents.x(), -contents.y());
1487     uiViewport.move(-contents.x(), -contents.y());
1488
1489     graphicsContext.save();
1490
1491     // Draw a blue rect for the webkit thread viewport.
1492     graphicsContext.setStrokeColor(WebCore::Color(0, 0, 255), WebCore::ColorSpaceDeviceRGB);
1493     graphicsContext.strokeRect(transformation.mapRect(wkViewport), 1.0);
1494
1495     // Draw a red rect for the ui thread viewport.
1496     graphicsContext.setStrokeColor(WebCore::Color(255, 0, 0), WebCore::ColorSpaceDeviceRGB);
1497     graphicsContext.strokeRect(transformation.mapRect(uiViewport), 1.0);
1498
1499     graphicsContext.restore();
1500
1501     delete bufferPlatformGraphicsContext;
1502     releaseBufferDrawable(windowBuffer);
1503 #endif
1504
1505 #if DEBUG_CHECKERBOARD
1506     static double lastCheckeredTime = 0;
1507
1508     if (blitCheckered && !lastCheckeredTime) {
1509         lastCheckeredTime = WTF::currentTime();
1510         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
1511             "Blitting checkered pattern at %f\n", lastCheckeredTime);
1512     } else if (blitCheckered && lastCheckeredTime) {
1513         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
1514             "Blitting checkered pattern at %f\n", WTF::currentTime());
1515     } else if (!blitCheckered && lastCheckeredTime) {
1516         double time = WTF::currentTime();
1517         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
1518             "Blitting over checkered pattern at %f took %f\n", time, time - lastCheckeredTime);
1519         lastCheckeredTime = 0;
1520     }
1521 #endif
1522
1523     invalidateWindow(dstRect);
1524
1525     if (blittingDirectlyToCompositingWindow) {
1526         pthread_mutex_lock(&m_blitGenerationLock);
1527
1528         ++m_blitGeneration;
1529         for (unsigned int i = 0; i < blittedTiles.size(); ++i)
1530             blittedTiles[i]->setBlitGeneration(m_blitGeneration);
1531
1532         clock_gettime(CLOCK_REALTIME, &m_currentBlitEnd);
1533         m_currentBlitEnd.tv_nsec += 30 * 1000 * 1000;
1534         if (m_currentBlitEnd.tv_nsec >= 1000000000L) {
1535             m_currentBlitEnd.tv_sec  += 1;
1536             m_currentBlitEnd.tv_nsec -= 1000000000L;
1537         }
1538
1539         pthread_mutex_unlock(&m_blitGenerationLock);
1540         pthread_cond_signal(&m_blitGenerationCond);
1541     }
1542 }
1543
1544 Platform::IntRect BackingStorePrivate::blitTileRect(TileBuffer* tileBuffer,
1545                                                    const TileRect& tileRect,
1546                                                    const Platform::IntPoint& origin,
1547                                                    const WebCore::TransformationMatrix& matrix,
1548                                                    BackingStoreGeometry* state)
1549 {
1550     if (!m_webPage->isVisible() || !isActive())
1551         return Platform::IntRect();
1552
1553     Platform::IntRect dirtyTileRect = tileRect.second;
1554
1555     // This dirty rect is in tile coordinates, but it needs to be in
1556     // transformed contents coordinates.
1557     Platform::IntRect dirtyRect = mapFromTilesToTransformedContents(tileRect, state->backingStoreRect());
1558
1559     // Now, this dirty rect is in transformed coordinates relative to the
1560     // transformed contents, but ultimately it needs to be transformed
1561     // coordinates relative to the viewport.
1562     dirtyRect.move(-origin.x(), -origin.y());
1563     dirtyRect = matrix.mapRect(dirtyRect);
1564
1565     if (!matrix.isIdentity()) {
1566         // Because of rounding it is possible that dirtyRect could be off-by-one larger
1567         // than the surface size of the dst buffer. We prevent this here, by clamping
1568         // it to ensure that can't happen.
1569         dirtyRect.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
1570     }
1571
1572     ASSERT(!dirtyRect.isEmpty());
1573     ASSERT(!dirtyTileRect.isEmpty());
1574     if (dirtyRect.isEmpty() || dirtyTileRect.isEmpty())
1575         return Platform::IntRect();
1576
1577     blitToWindow(dirtyRect, tileBuffer->nativeBuffer(), dirtyTileRect,
1578                  false /*blend*/, 255);
1579     return dirtyRect;
1580 }
1581
1582 #if USE(ACCELERATED_COMPOSITING)
1583 void BackingStorePrivate::blendCompositingSurface(const Platform::IntRect& dstRect)
1584 {
1585     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
1586         typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)(const Platform::IntRect&);
1587         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
1588             BlackBerry::Platform::createMethodCallMessage<FunctionType, BackingStorePrivate, Platform::IntRect>(
1589                 &BackingStorePrivate::blendCompositingSurface, this, dstRect));
1590         return;
1591     }
1592
1593     BackingStoreCompositingSurface* compositingSurface =
1594         SurfacePool::globalSurfacePool()->compositingSurface();
1595
1596     if (!compositingSurface || !m_webPage->isVisible())
1597         return;
1598
1599     WebCore::LayerRenderingResults lastCompositingResults = m_webPage->d->lastCompositingResults();
1600     for (size_t i = 0; i < lastCompositingResults.holePunchRectSize(); i++) {
1601         Platform::IntRect holePunchRect = lastCompositingResults.holePunchRect(i);
1602
1603         holePunchRect.intersect(dstRect);
1604         holePunchRect.intersect(Platform::IntRect(
1605             Platform::IntPoint(0, 0), surfaceSize()));
1606
1607         if (!holePunchRect.isEmpty())
1608             clearWindow(holePunchRect, 0, 0, 0, 0);
1609     }
1610
1611     CompositingSurfaceBuffer* frontBuffer = compositingSurface->frontBuffer();
1612
1613     IntRectList rects = lastCompositingResults.dirtyRegion.rects();
1614     for (size_t i = 0; i < rects.size(); ++i) {
1615         rects[i].intersect(dstRect);
1616 #if DEBUG_COMPOSITING_DIRTY_REGION
1617         clearBuffer(buffer(), rects[i], 255, 0, 0, 128);
1618 #endif
1619         blitToWindow(rects[i], frontBuffer->nativeBuffer(), rects[i], true /*blend*/, 255);
1620     }
1621 }
1622
1623 void BackingStorePrivate::clearCompositingSurface()
1624 {
1625     BackingStoreCompositingSurface* compositingSurface =
1626         SurfacePool::globalSurfacePool()->compositingSurface();
1627
1628     if (!compositingSurface)
1629         return;
1630
1631     CompositingSurfaceBuffer* frontBuffer = compositingSurface->frontBuffer();
1632     BlackBerry::Platform::Graphics::clearBuffer(frontBuffer->nativeBuffer(), Platform::IntRect(Platform::IntPoint(), frontBuffer->surfaceSize()), 0, 0, 0, 0);
1633 }
1634 #endif // USE(ACCELERATED_COMPOSITING)
1635
1636 void BackingStorePrivate::blitHorizontalScrollbar(const Platform::IntPoint& scrollPosition)
1637 {
1638     if (!m_webPage->isVisible())
1639         return;
1640
1641     ASSERT(m_client->scrollsHorizontally());
1642
1643     m_webPage->client()->drawHorizontalScrollbar();
1644 }
1645
1646 void BackingStorePrivate::blitVerticalScrollbar(const Platform::IntPoint& scrollPosition)
1647 {
1648     if (!m_webPage->isVisible())
1649         return;
1650
1651     ASSERT(m_client->scrollsVertically());
1652
1653     m_webPage->client()->drawVerticalScrollbar();
1654 }
1655
1656 bool BackingStorePrivate::isTileVisible(const TileIndex& index) const
1657 {
1658     TileRect tileRect;
1659     tileRect.first = index;
1660     tileRect.second = this->tileRect();
1661     return mapFromTilesToTransformedContents(tileRect).intersects(visibleContentsRect());
1662 }
1663
1664 bool BackingStorePrivate::isTileVisible(const Platform::IntPoint& origin) const
1665 {
1666     return Platform::IntRect(origin, tileSize()).intersects(visibleContentsRect());
1667 }
1668
1669 Platform::IntRect BackingStorePrivate::visibleTilesRect() const
1670 {
1671     BackingStoreGeometry* currentState = frontState();
1672     TileMap currentMap = currentState->tileMap();
1673
1674     Platform::IntRect rect;
1675     TileMap::const_iterator end = currentMap.end();
1676     for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
1677         TileRect tileRect;
1678         tileRect.first = it->first;
1679         tileRect.second = this->tileRect();
1680         Platform::IntRect tile = mapFromTilesToTransformedContents(tileRect);
1681         if (tile.intersects(visibleContentsRect()))
1682             rect = Platform::unionOfRects(rect, tile);
1683     }
1684     return rect;
1685 }
1686
1687 Platform::IntRect BackingStorePrivate::tileVisibleContentsRect(const TileIndex& index) const
1688 {
1689     if (!isTileVisible(index))
1690         return Platform::IntRect();
1691
1692     return tileContentsRect(index, visibleContentsRect());
1693 }
1694
1695 Platform::IntRect BackingStorePrivate::tileUnclippedVisibleContentsRect(const TileIndex& index) const
1696 {
1697     if (!isTileVisible(index))
1698         return Platform::IntRect();
1699
1700     return tileContentsRect(index, unclippedVisibleContentsRect());
1701 }
1702
1703 Platform::IntRect BackingStorePrivate::tileContentsRect(const TileIndex& index,
1704                                                        const Platform::IntRect& contents) const
1705 {
1706     return tileContentsRect(index, contents, frontState());
1707 }
1708
1709 Platform::IntRect BackingStorePrivate::tileContentsRect(const TileIndex& index,
1710                                                        const Platform::IntRect& contents,
1711                                                        BackingStoreGeometry* state) const
1712 {
1713     TileRectList tileRectList = mapFromTransformedContentsToTiles(contents, state);
1714     for (size_t i = 0; i < tileRectList.size(); ++i) {
1715         TileRect tileRect = tileRectList[i];
1716         if (index == tileRect.first)
1717             return tileRect.second;
1718     }
1719     return Platform::IntRect();
1720 }
1721
1722 void BackingStorePrivate::resetRenderQueue()
1723 {
1724     m_renderQueue->reset();
1725 }
1726
1727 void BackingStorePrivate::clearVisibleZoom()
1728 {
1729     m_renderQueue->clearVisibleZoom();
1730 }
1731
1732 void BackingStorePrivate::resetTiles(bool resetBackground)
1733 {
1734     BackingStoreGeometry* currentState = frontState();
1735     TileMap currentMap = currentState->tileMap();
1736
1737     TileMap::const_iterator end = currentMap.end();
1738     for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it)
1739         resetTile(it->first, it->second, resetBackground);
1740 }
1741
1742 void BackingStorePrivate::updateTiles(bool updateVisible, bool immediate)
1743 {
1744     if (!isActive())
1745         return;
1746
1747     BackingStoreGeometry* currentState = frontState();
1748     TileMap currentMap = currentState->tileMap();
1749
1750     TileMap::const_iterator end = currentMap.end();
1751     for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
1752         bool isVisible = isTileVisible(it->first);
1753         if (!updateVisible && isVisible)
1754             continue;
1755         updateTile(it->first, immediate);
1756     }
1757 }
1758
1759 void BackingStorePrivate::updateTilesForScrollOrNotRenderedRegion(bool checkLoading)
1760 {
1761     // This method looks at all the tiles and if they are visible, but not completely
1762     // rendered or we are loading, then it updates them. For all tiles, visible and
1763     // non-visible, if a previous attempt was made to render them during a regular
1764     // render job, but they were not visible at the time, then update them and if
1765     // they are currently visible, reset them.
1766
1767     BackingStoreGeometry* currentState = frontState();
1768     TileMap currentMap = currentState->tileMap();
1769     Platform::IntRect backingStoreRect = currentState->backingStoreRect();
1770
1771     bool isLoading = m_client->loadState() == WebPagePrivate::Committed;
1772     bool forceVisible = checkLoading && isLoading;
1773
1774     TileMap::const_iterator end = currentMap.end();
1775     for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
1776         TileIndex index = it->first;
1777         BackingStoreTile* tile = it->second;
1778         bool isVisible = isTileVisible(index);
1779         // The rect in transformed contents coordinates.
1780         Platform::IntRect rect(originOfTile(index), tileSize());
1781         if (tile->isCommitted()
1782             && m_renderQueue->regularRenderJobsPreviouslyAttemptedButNotRendered(rect)) {
1783             // If the render queue previously tried to render this tile, but the
1784             // tile wasn't visible at the time we can't simply restore the tile
1785             // since the content is now invalid as far as WebKit is concerned.
1786             // Instead, we clear that part of the tile if it is visible and then
1787             // put the tile in the render queue again.
1788             if (isVisible) {
1789                 // Intersect the tile with the not rendered region to get the areas
1790                 // of the tile that we need to clear.
1791                 Platform::IntRectRegion tileNotRenderedRegion
1792                     = Platform::IntRectRegion::intersectRegions(
1793                         m_renderQueue->regularRenderJobsNotRenderedRegion(),
1794                         rect);
1795                 clearAndUpdateTileOfNotRenderedRegion(index,
1796                                                       tile,
1797                                                       tileNotRenderedRegion,
1798                                                       backingStoreRect,
1799                                                       false /*update*/);
1800 #if DEBUG_BACKINGSTORE
1801                 Platform::IntRect extents = tileNotRenderedRegion.extents();
1802                 BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
1803                     "BackingStorePrivate::updateTilesForScroll did clear tile %d,%d %dx%d",
1804                     extents.x(), extents.y(), extents.width(), extents.height());
1805 #endif
1806             }
1807             updateTile(index, false /*immediate*/);
1808         } else if (isVisible
1809             && (forceVisible || !tile->frontBuffer()->isRendered(tileVisibleContentsRect(index)))
1810             && !isCurrentVisibleJob(index, tile, backingStoreRect))
1811             updateTile(index, false /*immediate*/);
1812     }
1813 }
1814
1815 void BackingStorePrivate::resetTile(const TileIndex& index, BackingStoreTile* tile, bool resetBackground)
1816 {
1817     if (!m_webPage->isVisible())
1818         return;
1819
1820     if (!isActive()) {
1821         m_webPage->d->setShouldResetTilesWhenShown(true);
1822         return;
1823     }
1824
1825     TileRect tileRect;
1826     tileRect.first = index;
1827     tileRect.second = this->tileRect();
1828     // Only clear regular render jobs if we're clearing the background too.
1829     m_renderQueue->clear(mapFromTilesToTransformedContents(tileRect), resetBackground /*clearRegularRenderJobs*/);
1830     if (resetBackground)
1831         tile->reset();
1832 }
1833
1834 void BackingStorePrivate::updateTile(const TileIndex& index, bool immediate)
1835 {
1836     if (!isActive())
1837         return;
1838
1839     TileRect tileRect;
1840     tileRect.first = index;
1841     tileRect.second = this->tileRect();
1842     Platform::IntRect updateRect = mapFromTilesToTransformedContents(tileRect);
1843     RenderQueue::JobType jobType = isTileVisible(index) ? RenderQueue::VisibleScroll : RenderQueue::NonVisibleScroll;
1844     if (immediate)
1845         render(updateRect);
1846     else
1847         m_renderQueue->addToQueue(jobType, updateRect);
1848 }
1849
1850 void BackingStorePrivate::updateTile(const Platform::IntPoint& origin, bool immediate)
1851 {
1852     if (!isActive())
1853         return;
1854
1855     Platform::IntRect updateRect = Platform::IntRect(origin, tileSize());
1856     RenderQueue::JobType jobType = isTileVisible(origin) ? RenderQueue::VisibleScroll : RenderQueue::NonVisibleScroll;
1857     if (immediate)
1858         render(updateRect);
1859     else
1860         m_renderQueue->addToQueue(jobType, updateRect);
1861 }
1862
1863 Platform::IntRect BackingStorePrivate::mapFromTilesToTransformedContents(const BackingStorePrivate::TileRect& tileRect) const
1864 {
1865     return mapFromTilesToTransformedContents(tileRect, frontState()->backingStoreRect());
1866 }
1867
1868 Platform::IntRect BackingStorePrivate::mapFromTilesToTransformedContents(const BackingStorePrivate::TileRect& tileRect, const Platform::IntRect& backingStoreRect) const
1869 {
1870     TileIndex index = tileRect.first;
1871     Platform::IntRect rect = tileRect.second;
1872     // The origin of the tile including the backing store offset.
1873     const Platform::IntPoint originOfTile = this->originOfTile(index, backingStoreRect);
1874     rect.move(originOfTile.x(), originOfTile.y());
1875     return rect;
1876 }
1877
1878 BackingStorePrivate::TileRectList BackingStorePrivate::mapFromTransformedContentsToAbsoluteTileBoundaries(const Platform::IntRect& rect) const
1879 {
1880     if (!m_webPage->isVisible() || !isActive()) {
1881         ASSERT_NOT_REACHED();
1882         return TileRectList();
1883     }
1884
1885     TileRectList tileRectList;
1886     int firstXOffset = rect.x() / tileWidth();
1887     int firstYOffset = rect.y() / tileHeight();
1888     int lastXOffset = (rect.right() - 1) / tileWidth();
1889     int lastYOffset = (rect.bottom() - 1) / tileHeight();
1890     for (int i = firstXOffset; i <= lastXOffset; ++i) {
1891         for (int j = firstYOffset; j <= lastYOffset; ++j) {
1892             const int dstX = (i == firstXOffset) ? rect.x() : i * tileWidth();
1893             const int dstY = (j == firstYOffset) ? rect.y() : j * tileHeight();
1894             const int dstRight = (i == lastXOffset) ? rect.right() : (i + 1) * tileWidth();
1895             const int dstBottom = (j == lastYOffset) ? rect.bottom() : (j + 1) * tileHeight();
1896             const int srcX = dstX % tileWidth();
1897             const int srcY = dstY % tileHeight();
1898             TileRect tileRect;
1899             tileRect.first = TileIndex(i, j);
1900             tileRect.second = Platform::IntRect(srcX, srcY, dstRight - dstX, dstBottom - dstY);
1901             tileRectList.append(tileRect);
1902         }
1903     }
1904     return tileRectList;
1905 }
1906
1907
1908 BackingStorePrivate::TileRectList BackingStorePrivate::mapFromTransformedContentsToTiles(const Platform::IntRect& rect) const
1909 {
1910     return mapFromTransformedContentsToTiles(rect, frontState());
1911 }
1912
1913 BackingStorePrivate::TileRectList BackingStorePrivate::mapFromTransformedContentsToTiles(const Platform::IntRect& rect, BackingStoreGeometry* state) const
1914 {
1915     TileMap tileMap = state->tileMap();
1916
1917     TileRectList tileRectList;
1918     TileMap::const_iterator end = tileMap.end();
1919     for (TileMap::const_iterator it = tileMap.begin(); it != end; ++it) {
1920         TileIndex index = it->first;
1921         BackingStoreTile* tile = it->second;
1922
1923         // Need to map the rect to tile coordinates.
1924         Platform::IntRect r = rect;
1925
1926         // The origin of the tile including the backing store offset.
1927         const Platform::IntPoint originOfTile = this->originOfTile(index, state->backingStoreRect());
1928
1929         r.move(-(originOfTile.x()), -(originOfTile.y()));
1930
1931         // Do we intersect the current tile or no?
1932         r.intersect(tile->rect());
1933         if (r.isEmpty())
1934             continue;
1935
1936         // If we do append to list and Voila!
1937         TileRect tileRect;
1938         tileRect.first = index;
1939         tileRect.second = r;
1940         tileRectList.append(tileRect);
1941     }
1942     return tileRectList;
1943 }
1944
1945 void BackingStorePrivate::updateTileMatrixIfNeeded()
1946 {
1947     // This will update the tile matrix.
1948     scrollBackingStore(0, 0);
1949 }
1950
1951 void BackingStorePrivate::contentsSizeChanged(const Platform::IntSize&)
1952 {
1953     updateTileMatrixIfNeeded();
1954 }
1955
1956 void BackingStorePrivate::scrollChanged(const Platform::IntPoint&)
1957 {
1958     // FIXME: Need to do anything here?
1959 }
1960
1961 void BackingStorePrivate::transformChanged()
1962 {
1963     if (!m_webPage->isVisible())
1964         return;
1965
1966     if (!isActive()) {
1967         m_renderQueue->reset();
1968         m_renderQueue->addToQueue(RenderQueue::VisibleZoom, visibleContentsRect());
1969         m_webPage->d->setShouldResetTilesWhenShown(true);
1970         return;
1971     }
1972
1973     BackingStoreGeometry* currentState = frontState();
1974     TileMap currentMap = currentState->tileMap();
1975
1976     bool hasCurrentVisibleZoomJob = m_renderQueue->hasCurrentVisibleZoomJob();
1977     bool isLoading = m_client->isLoading();
1978     if (isLoading) {
1979         if (!hasCurrentVisibleZoomJob)
1980             m_visibleTileBufferRect = visibleContentsRect(); // Cache this for blitVisibleContents.
1981
1982         // Add the currently visible tiles to the render queue as visible zoom jobs.
1983         TileRectList tileRectList = mapFromTransformedContentsToTiles(visibleContentsRect());
1984         for (size_t i = 0; i < tileRectList.size(); ++i) {
1985             TileRect tileRect = tileRectList[i];
1986             TileIndex index = tileRect.first;
1987             Platform::IntRect dirtyTileRect = tileRect.second;
1988             BackingStoreTile* tile = currentMap.get(index);
1989
1990             // Invalidate the whole rect.
1991             tileRect.second = this->tileRect();
1992             Platform::IntRect wholeRect = mapFromTilesToTransformedContents(tileRect);
1993             m_renderQueue->addToQueue(RenderQueue::VisibleZoom, wholeRect);
1994
1995             // Copy the visible contents into the visibleTileBuffer if we don't have
1996             // any current visible zoom jobs.
1997             if (!hasCurrentVisibleZoomJob) {
1998                 // Map to the destination's coordinate system.
1999                 Platform::IntPoint difference = this->originOfTile(index) - m_visibleTileBufferRect.location();
2000                 Platform::IntSize offset = Platform::IntSize(difference.x(), difference.y());
2001                 Platform::IntRect dirtyRect = dirtyTileRect;
2002                 dirtyRect.move(offset.width(), offset.height());
2003
2004                 BackingStoreTile* visibleTileBuffer
2005                     = SurfacePool::globalSurfacePool()->visibleTileBuffer();
2006                 ASSERT(visibleTileBuffer->size() == Platform::IntSize(m_webPage->d->transformedViewportSize()));
2007                 BlackBerry::Platform::Graphics::blitToBuffer(
2008                     visibleTileBuffer->frontBuffer()->nativeBuffer(), dirtyRect,
2009                     tile->frontBuffer()->nativeBuffer(), dirtyTileRect);
2010             }
2011         }
2012     }
2013
2014     m_renderQueue->reset();
2015     resetTiles(true /*resetBackground*/);
2016 }
2017
2018 void BackingStorePrivate::orientationChanged()
2019 {
2020     updateTileMatrixIfNeeded();
2021     createVisibleTileBuffer();
2022 }
2023
2024 void BackingStorePrivate::actualVisibleSizeChanged(const Platform::IntSize& size)
2025 {
2026 }
2027
2028 static void createVisibleTileBufferForWebPage(WebPagePrivate* page)
2029 {
2030     ASSERT(page);
2031     SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
2032     surfacePool->initializeVisibleTileBuffer(page->transformedViewportSize());
2033 }
2034
2035 void BackingStorePrivate::createSurfaces()
2036 {
2037     BackingStoreGeometry* currentState = frontState();
2038     TileMap currentMap = currentState->tileMap();
2039
2040     ASSERT(currentMap.isEmpty());
2041
2042     if (m_webPage->isVisible()) {
2043         // This method is only to be called as part of setting up a new web page instance and
2044         // before said instance is made visible so as to ensure a consistent definition of web
2045         // page visibility. That is, a web page is said to be visible when explicitly made visible.
2046         ASSERT_NOT_REACHED();
2047         return;
2048     }
2049
2050     SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
2051     surfacePool->initialize(tileSize());
2052
2053     if (surfacePool->isEmpty()) // Settings specify 0 tiles / no backing store.
2054         return;
2055
2056     const Divisor divisor = bestDivisor(expandedContentsSize(), tileWidth(), tileHeight(), minimumNumberOfTilesWide(), minimumNumberOfTilesHigh(), m_preferredTileMatrixDimension);
2057
2058     int numberOfTilesWide = divisor.first;
2059     int numberOfTilesHigh = divisor.second;
2060
2061     const SurfacePool::TileList tileList = surfacePool->tileList();
2062     ASSERT(static_cast<int>(tileList.size()) >= (numberOfTilesWide * numberOfTilesHigh));
2063
2064     TileMap newTileMap;
2065     for (int y = 0; y < numberOfTilesHigh; ++y) {
2066         for (int x = 0; x < numberOfTilesWide; ++x) {
2067             TileIndex index(x, y);
2068             newTileMap.add(index, tileList.at(x + y * numberOfTilesWide));
2069         }
2070     }
2071
2072     // Set the initial state of the backingstore geometry.
2073     backState()->setNumberOfTilesWide(divisor.first);
2074     backState()->setNumberOfTilesHigh(divisor.second);
2075     backState()->setTileMap(newTileMap);
2076
2077     // Swap back/front state.
2078     swapState();
2079
2080     createVisibleTileBufferForWebPage(m_webPage->d);
2081 }
2082
2083 void BackingStorePrivate::createVisibleTileBuffer()
2084 {
2085     if (!m_webPage->isVisible() || !isActive())
2086         return;
2087
2088     createVisibleTileBufferForWebPage(m_webPage->d);
2089 }
2090
2091 Platform::IntPoint BackingStorePrivate::originOfTile(const TileIndex& index) const
2092 {
2093     return originOfTile(index, frontState()->backingStoreRect());
2094 }
2095
2096 Platform::IntPoint BackingStorePrivate::originOfTile(const TileIndex& index, const Platform::IntRect& backingStoreRect) const
2097 {
2098     return Platform::IntPoint(backingStoreRect.x() + (index.i() * tileWidth()),
2099                               backingStoreRect.y() + (index.j() * tileHeight()));
2100 }
2101
2102 int BackingStorePrivate::minimumNumberOfTilesWide() const
2103 {
2104     // The minimum number of tiles wide required to fill the viewport + 1 tile extra to allow scrolling.
2105     return static_cast<int>(ceilf(m_client->transformedViewportSize().width() / static_cast<float>(tileWidth()))) + 1;
2106 }
2107
2108 int BackingStorePrivate::minimumNumberOfTilesHigh() const
2109 {
2110     // The minimum number of tiles high required to fill the viewport + 1 tile extra to allow scrolling.
2111     return static_cast<int>(ceilf(m_client->transformedViewportSize().height() / static_cast<float>(tileHeight()))) + 1;
2112 }
2113
2114 Platform::IntSize BackingStorePrivate::expandedContentsSize() const
2115 {
2116     return m_client->transformedContentsSize().expandedTo(m_client->transformedViewportSize());
2117 }
2118
2119 int BackingStorePrivate::tileWidth()
2120 {
2121     static int tileWidth = BlackBerry::Platform::Graphics::Screen::primaryScreen()->landscapeWidth();
2122     return tileWidth;
2123 }
2124
2125 int BackingStorePrivate::tileHeight()
2126 {
2127     static int tileHeight = BlackBerry::Platform::Graphics::Screen::primaryScreen()->landscapeHeight();
2128     return tileHeight;
2129 }
2130
2131 Platform::IntSize BackingStorePrivate::tileSize()
2132 {
2133     return Platform::IntSize(tileWidth(), tileHeight());
2134 }
2135
2136 Platform::IntRect BackingStorePrivate::tileRect()
2137 {
2138     return Platform::IntRect(0, 0, tileWidth(), tileHeight());
2139 }
2140
2141 void BackingStorePrivate::renderContents(BlackBerry::Platform::Graphics::Buffer* tileBuffer,
2142                                          const Platform::IntPoint& surfaceOffset,
2143                                          const Platform::IntRect& contentsRect) const
2144 {
2145     // If tileBuffer == 0, we render directly to the window.
2146     if (!m_webPage->isVisible() && tileBuffer)
2147         return;
2148
2149 #if DEBUG_BACKINGSTORE
2150     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
2151                            "BackingStorePrivate::renderContents tileBuffer=0x%x surfaceOffset=(%d,%d) contentsRect=(%d,%d %dx%d)",
2152                            tileBuffer, surfaceOffset.x(), surfaceOffset.y(),
2153                            contentsRect.x(), contentsRect.y(), contentsRect.width(), contentsRect.height());
2154 #endif
2155
2156     // It is up to callers of this method to perform layout themselves!
2157     ASSERT(!m_webPage->d->mainFrame()->view()->needsLayout());
2158
2159     Platform::IntSize contentsSize = m_client->contentsSize();
2160     Color backgroundColor(m_webPage->settings()->backgroundColor());
2161
2162     BlackBerry::Platform::Graphics::Buffer* targetBuffer = tileBuffer
2163         ? tileBuffer
2164         : buffer();
2165
2166     if (contentsSize.isEmpty()
2167         || !Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedContentsSize()).contains(contentsRect)
2168         || backgroundColor.hasAlpha()) {
2169         // Clear the area if it's not fully covered by (opaque) contents.
2170         BlackBerry::Platform::IntRect clearRect = BlackBerry::Platform::IntRect(
2171             contentsRect.x() - surfaceOffset.x(), contentsRect.y() - surfaceOffset.y(),
2172             contentsRect.width(), contentsRect.height());
2173
2174         BlackBerry::Platform::Graphics::clearBuffer(targetBuffer, clearRect,
2175             backgroundColor.red(), backgroundColor.green(),
2176             backgroundColor.blue(), backgroundColor.alpha());
2177     }
2178
2179     if (contentsSize.isEmpty())
2180         return;
2181
2182 #if USE(ACCELERATED_COMPOSITING)
2183     // When committing the pending accelerated compositing layer changes, it's
2184     // necessary to draw the new layer appearance. This is normally done as
2185     // part of a blit, but if no blit happens because of this rendering, for
2186     // example because we're rendering an offscreen rectangle, someone needs to
2187     // catch this flag and make sure those layers get drawn.
2188     // This is just a complicated way to do
2189     // "if (commitRootLayerIfNeeded()) drawLayersOnCommit();"
2190     if (m_webPage->d->commitRootLayerIfNeeded())
2191         m_needsDrawLayersOnCommit = true;
2192 #endif
2193
2194     BlackBerry::Platform::Graphics::Drawable* bufferDrawable =
2195         BlackBerry::Platform::Graphics::lockBufferDrawable(targetBuffer);
2196
2197     PlatformGraphicsContext* bufferPlatformGraphicsContext = bufferDrawable
2198         ? SurfacePool::globalSurfacePool()->createPlatformGraphicsContext(bufferDrawable)
2199         : 0;
2200     PlatformGraphicsContext* targetPlatformGraphicsContext = bufferPlatformGraphicsContext
2201         ? bufferPlatformGraphicsContext
2202         : SurfacePool::globalSurfacePool()->lockTileRenderingSurface();
2203
2204     ASSERT(targetPlatformGraphicsContext);
2205
2206     {
2207         GraphicsContext graphicsContext(targetPlatformGraphicsContext);
2208
2209         // Believe it or not this is important since the WebKit Skia backend
2210         // doesn't store the original state unless you call save first :P
2211         graphicsContext.save();
2212
2213         // Translate context according to offset.
2214         graphicsContext.translate(-surfaceOffset.x(), -surfaceOffset.y());
2215
2216         // Add our transformation matrix as the global transform.
2217         AffineTransform affineTransform(
2218             m_webPage->d->transformationMatrix()->a(),
2219             m_webPage->d->transformationMatrix()->b(),
2220             m_webPage->d->transformationMatrix()->c(),
2221             m_webPage->d->transformationMatrix()->d(),
2222             m_webPage->d->transformationMatrix()->e(),
2223             m_webPage->d->transformationMatrix()->f());
2224         graphicsContext.concatCTM(affineTransform);
2225
2226         // Now that the matrix is applied we need untranformed contents coordinates.
2227         Platform::IntRect untransformedContentsRect = m_webPage->d->mapFromTransformed(contentsRect);
2228
2229         // We extract from the contentsRect but draw a slightly larger region than
2230         // we were told to, in order to avoid pixels being rendered only partially.
2231         const int atLeastOneDevicePixel =
2232             static_cast<int>(ceilf(1.0 / m_webPage->d->transformationMatrix()->a()));
2233         untransformedContentsRect.inflate(atLeastOneDevicePixel, atLeastOneDevicePixel);
2234
2235         // Make sure the untransformed rectangle for the (slightly larger than
2236         // initially requested) repainted region is within the bounds of the page.
2237         untransformedContentsRect.intersect(Platform::IntRect(Platform::IntPoint(0, 0), contentsSize));
2238
2239         // Some WebKit painting backends *cough* Skia *cough* don't set this automatically
2240         // to the dirtyRect so do so here explicitly.
2241         graphicsContext.clip(untransformedContentsRect);
2242
2243         // Take care of possible left overflow on RTL page.
2244         if (int leftOverFlow = m_client->frame()->view()->minimumScrollPosition().x()) {
2245             untransformedContentsRect.move(leftOverFlow, 0);
2246             graphicsContext.translate(-leftOverFlow, 0);
2247         }
2248
2249         // Let WebCore render the page contents into the drawing surface.
2250         m_client->frame()->view()->paintContents(&graphicsContext, untransformedContentsRect);
2251
2252 #if ENABLE(INSPECTOR)
2253         if (m_webPage->d->m_page->inspectorController()->enabled()) {
2254             WebCore::IntPoint scrollPosition = m_client->frame()->view()->scrollPosition();
2255             graphicsContext.translate(scrollPosition.x(), scrollPosition.y());
2256             m_webPage->d->m_page->inspectorController()->drawHighlight(graphicsContext);
2257         }
2258 #endif
2259
2260         graphicsContext.restore();
2261     }
2262
2263     // Grab the requested region from the drawing surface into the tile image.
2264
2265     delete bufferPlatformGraphicsContext;
2266
2267     if (bufferDrawable)
2268         releaseBufferDrawable(targetBuffer);
2269     else {
2270         const Platform::IntPoint dstPoint(contentsRect.x() - surfaceOffset.x(),
2271                                           contentsRect.y() - surfaceOffset.y());
2272         const Platform::IntRect dstRect(dstPoint, contentsRect.size());
2273         const Platform::IntRect srcRect = dstRect;
2274
2275         // If we couldn't directly draw to the buffer, copy from the drawing surface.
2276         SurfacePool::globalSurfacePool()->releaseTileRenderingSurface(targetPlatformGraphicsContext);
2277         BlackBerry::Platform::Graphics::blitToBuffer(targetBuffer, dstRect, BlackBerry::Platform::Graphics::drawingSurface(), srcRect);
2278     }
2279 }
2280
2281 #if DEBUG_FAT_FINGERS
2282 static void drawDebugRect(BlackBerry::Platform::Graphics::Buffer* dstBuffer, const Platform::IntRect& dstRect, const Platform::IntRect& srcRect, unsigned char red, unsigned char green, unsigned char blue)
2283 {
2284     Platform::IntRect drawRect(srcRect);
2285     drawRect.intersect(dstRect);
2286     if (!drawRect.isEmpty())
2287         BlackBerry::Platform::Graphics::clearBuffer(dstBuffer, drawRect, red, green, blue, 128);
2288 }
2289 #endif
2290
2291 void BackingStorePrivate::blitToWindow(const Platform::IntRect& dstRect,
2292                                        const BlackBerry::Platform::Graphics::Buffer* srcBuffer,
2293                                        const Platform::IntRect& srcRect,
2294                                        bool blend,
2295                                        unsigned char globalAlpha)
2296 {
2297     ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
2298
2299     windowFrontBufferState()->clearBlittedRegion(dstRect);
2300     windowBackBufferState()->addBlittedRegion(dstRect);
2301
2302     BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
2303     ASSERT(dstBuffer);
2304     ASSERT(srcBuffer);
2305     if (!dstBuffer)
2306         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't blitToWindow");
2307
2308     BlackBerry::Platform::Graphics::BlendMode blendMode = blend
2309         ? BlackBerry::Platform::Graphics::SourceOver
2310         : BlackBerry::Platform::Graphics::SourceCopy;
2311
2312     BlackBerry::Platform::Graphics::blitToBuffer(dstBuffer, dstRect, srcBuffer, srcRect, blendMode, globalAlpha);
2313
2314 #if DEBUG_FAT_FINGERS
2315     drawDebugRect(dstBuffer, dstRect, FatFingers::m_debugFatFingerRect, 210, 210, 250);
2316     drawDebugRect(dstBuffer, dstRect, Platform::IntRect(FatFingers::m_debugFatFingerClickPosition, Platform::IntSize(3, 3)), 0, 0, 0);
2317     drawDebugRect(dstBuffer, dstRect, Platform::IntRect(FatFingers::m_debugFatFingerAdjustedPosition, Platform::IntSize(5, 5)), 100, 100, 100);
2318 #endif
2319
2320 }
2321
2322 void BackingStorePrivate::checkerWindow(const Platform::IntRect& dstRect,
2323                                         const Platform::IntPoint& contentsOrigin,
2324                                         double contentsScale)
2325 {
2326     ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
2327
2328     windowFrontBufferState()->clearBlittedRegion(dstRect);
2329     windowBackBufferState()->addBlittedRegion(dstRect);
2330
2331     BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
2332     ASSERT(dstBuffer);
2333     if (!dstBuffer)
2334         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't checkerWindow");
2335
2336     Color color(m_webPage->settings()->backgroundColor());
2337     unsigned char alpha = color.alpha();
2338     BlackBerry::Platform::Graphics::checkerBuffer(dstBuffer, dstRect, contentsOrigin, contentsScale, alpha);
2339 }
2340
2341 void BackingStorePrivate::invalidateWindow()
2342 {
2343     // Grab a rect appropriate for the current thread.
2344     if (BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread())
2345         invalidateWindow(m_webPage->client()->userInterfaceBlittedDestinationRect());
2346     else
2347         invalidateWindow(Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedViewportSize()));
2348 }
2349
2350 void BackingStorePrivate::invalidateWindow(const Platform::IntRect& dst)
2351 {
2352     if (dst.isEmpty())
2353         return;
2354
2355     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread() && !shouldDirectRenderingToWindow()) {
2356         // This needs to be sync in order to swap the recently drawn thing...
2357         // This will only be called from WebKit thread during direct rendering.
2358         typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)(const Platform::IntRect&);
2359         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
2360             BlackBerry::Platform::createMethodCallMessage<FunctionType, BackingStorePrivate, Platform::IntRect>(
2361                 &BackingStorePrivate::invalidateWindow, this, dst));
2362         return;
2363     }
2364
2365 #if DEBUG_BACKINGSTORE
2366     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::invalidateWindow dst = %s", dst.toString().c_str());
2367 #endif
2368
2369     // Since our window may also be double buffered, we need to also copy the
2370     // front buffer's contents to the back buffer before we swap them. It is
2371     // analogous to what we do with our double buffered tiles by calling
2372     // copyPreviousContentsToBackingSurfaceOfTile(). It only affects partial
2373     // screen updates since when we are scrolling or zooming, the whole window
2374     // is invalidated anyways and no copying is needed.
2375     copyPreviousContentsToBackSurfaceOfWindow();
2376
2377     Platform::IntRect dstRect = dst;
2378
2379     Platform::IntRect viewportRect(Platform::IntPoint(0, 0), m_client->transformedViewportSize());
2380     dstRect.intersect(viewportRect);
2381
2382     if (dstRect.width() <= 0 || dstRect.height() <= 0)
2383         return;
2384
2385 #if DEBUG_BACKINGSTORE
2386     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::invalidateWindow posting = %s", dstRect.toString().c_str());
2387 #endif
2388
2389     m_currentWindowBackBuffer = (m_currentWindowBackBuffer + 1) % 2;
2390     if (Window* window = m_webPage->client()->window())
2391         window->post(dstRect);
2392 }
2393
2394 void BackingStorePrivate::clearWindow()
2395 {
2396     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread() && !shouldDirectRenderingToWindow()) {
2397         typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)();
2398         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
2399             BlackBerry::Platform::createMethodCallMessage<FunctionType, BackingStorePrivate>(
2400                 &BackingStorePrivate::clearWindow, this));
2401         return;
2402     }
2403
2404     BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
2405     ASSERT(dstBuffer);
2406     if (!dstBuffer)
2407         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't clearWindow");
2408
2409     windowFrontBufferState()->clearBlittedRegion();
2410     windowBackBufferState()->addBlittedRegion(Platform::IntRect(
2411         Platform::IntPoint(0, 0), surfaceSize()));
2412
2413     Color color(m_webPage->settings()->backgroundColor());
2414     BlackBerry::Platform::Graphics::clearBuffer(dstBuffer,
2415         color.red(), color.green(), color.blue(), color.alpha());
2416 }
2417
2418 void BackingStorePrivate::clearWindow(const Platform::IntRect& rect,
2419                                       unsigned char red,
2420                                       unsigned char green,
2421                                       unsigned char blue,
2422                                       unsigned char alpha)
2423 {
2424     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread() && !shouldDirectRenderingToWindow()) {
2425         typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)(const Platform::IntRect&,
2426                                                                            unsigned char,
2427                                                                            unsigned char,
2428                                                                            unsigned char,
2429                                                                            unsigned char);
2430         BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
2431             BlackBerry::Platform::createMethodCallMessage<FunctionType,
2432                                                        BackingStorePrivate,
2433                                                        Platform::IntRect,
2434                                                        unsigned char,
2435                                                        unsigned char,
2436                                                        unsigned char,
2437                                                        unsigned char>(
2438                 &BackingStorePrivate::clearWindow, this, rect, red, green, blue, alpha));
2439         return;
2440     }
2441
2442     BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
2443     ASSERT(dstBuffer);
2444     if (!dstBuffer)
2445         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't clearWindow");
2446
2447     windowFrontBufferState()->clearBlittedRegion(rect);
2448     windowBackBufferState()->addBlittedRegion(rect);
2449
2450     BlackBerry::Platform::Graphics::clearBuffer(dstBuffer, rect, red, green, blue, alpha);
2451 }
2452
2453 bool BackingStorePrivate::isScrollingOrZooming() const
2454 {
2455     BackingStoreMutexLocker locker(const_cast<BackingStorePrivate*>(this));
2456     return m_isScrollingOrZooming;
2457 }
2458
2459 void BackingStorePrivate::setScrollingOrZooming(bool scrollingOrZooming, bool shouldBlit)
2460 {
2461     {
2462         BackingStoreMutexLocker locker(this);
2463         m_isScrollingOrZooming = scrollingOrZooming;
2464     }
2465
2466 #if !ENABLE_REPAINTONSCROLL
2467     m_suspendRenderJobs = scrollingOrZooming; // Suspend the rendering of everything.
2468 #endif
2469
2470     if (!m_webPage->settings()->shouldRenderAnimationsOnScrollOrZoom())
2471         m_suspendRegularRenderJobs = scrollingOrZooming; // Suspend the rendering of animations.
2472
2473     // Clear this flag since we don't care if the render queue is under pressure
2474     // or not since we are scrolling and it is more important to not lag than
2475     // it is to ensure animations achieve better framerates!
2476     if (scrollingOrZooming)
2477         m_renderQueue->setCurrentRegularRenderJobBatchUnderPressure(false);
2478 #if ENABLE_SCROLLBARS
2479     else if (shouldBlit && !shouldDirectRenderingToWindow())
2480         blitVisibleContents();
2481 #endif
2482 }
2483
2484 void BackingStorePrivate::lockBackingStore()
2485 {
2486     pthread_mutex_lock(&m_mutex);
2487 }
2488
2489 void BackingStorePrivate::unlockBackingStore()
2490 {
2491     pthread_mutex_unlock(&m_mutex);
2492 }
2493
2494 BackingStoreGeometry* BackingStorePrivate::frontState() const
2495 {
2496     return reinterpret_cast<BackingStoreGeometry*>(m_frontState);
2497 }
2498
2499 BackingStoreGeometry* BackingStorePrivate::backState() const
2500 {
2501     return reinterpret_cast<BackingStoreGeometry*>(m_backState);
2502 }
2503
2504 void BackingStorePrivate::swapState()
2505 {
2506     unsigned front = reinterpret_cast<unsigned>(frontState());
2507     unsigned back = reinterpret_cast<unsigned>(backState());
2508
2509     // Atomic change.
2510     _smp_xchg(&m_frontState, back);
2511     _smp_xchg(&m_backState, front);
2512     BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
2513 }
2514
2515 BackingStoreWindowBufferState* BackingStorePrivate::windowFrontBufferState() const
2516 {
2517     return &m_windowBufferState[(m_currentWindowBackBuffer + 1) % 2];
2518 }
2519
2520 BackingStoreWindowBufferState* BackingStorePrivate::windowBackBufferState() const
2521 {
2522     return &m_windowBufferState[m_currentWindowBackBuffer];
2523 }
2524
2525 #if USE(ACCELERATED_COMPOSITING)
2526 bool BackingStorePrivate::drawSubLayers()
2527 {
2528     ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
2529     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread())
2530         return false;
2531
2532     if (m_suspendBackingStoreUpdates && !isOpenGLCompositing())
2533         return false;
2534
2535     if (!m_webPage->d->compositor())
2536         return false;
2537
2538     Platform::IntRect dst = m_webPage->client()->userInterfaceBlittedDestinationRect();
2539     if (dst.isEmpty())
2540         return false;
2541
2542     Platform::IntRect src = m_webPage->client()->userInterfaceBlittedVisibleContentsRect();
2543     WebCore::FloatRect contentsRect = m_webPage->d->mapFromTransformedFloatRect(
2544         WebCore::FloatRect(WebCore::IntRect(src)));
2545     return m_webPage->d->compositor()->drawLayers(dst, contentsRect);
2546 }
2547
2548 bool BackingStorePrivate::drawLayersOnCommitIfNeeded()
2549 {
2550     // Check if rendering caused a commit and we need to redraw the layers
2551     if (!m_needsDrawLayersOnCommit)
2552         return false;
2553
2554     m_needsDrawLayersOnCommit = false;
2555     m_webPage->d->drawLayersOnCommit();
2556
2557     return true;
2558 }
2559
2560 void BackingStorePrivate::drawAndBlendLayersForDirectRendering(const Platform::IntRect& dirtyRect)
2561 {
2562     ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
2563     if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread())
2564         return;
2565
2566     // Because we're being called sync from the WebKit thread, we can use
2567     // regular WebPage size and transformation functions without concerns.
2568     WebCore::IntRect contentsRect = visibleContentsRect();
2569     WebCore::FloatRect untransformedContentsRect = m_webPage->d->mapFromTransformedFloatRect(WebCore::FloatRect(contentsRect));
2570     WebCore::IntRect contentsScreenRect = m_client->mapFromTransformedContentsToTransformedViewport(contentsRect);
2571     WebCore::IntRect dstRect = intersection(contentsScreenRect,
2572         WebCore::IntRect(WebCore::IntPoint(0, 0), m_webPage->d->transformedViewportSize()));
2573
2574     // Check if rendering caused a commit and we need to redraw the layers.
2575     m_needsDrawLayersOnCommit = false;
2576     if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
2577         compositor->drawLayers(dstRect, untransformedContentsRect);
2578
2579 #if ENABLE_COMPOSITING_SURFACE
2580     // See above comment about sync calling, visibleContentsRect() is safe here.
2581     Platform::IntRect visibleDirtyRect = dirtyRect;
2582     visibleDirtyRect.intersect(visibleContentsRect());
2583     visibleDirtyRect = m_client->mapFromTransformedContentsToTransformedViewport(visibleDirtyRect);
2584
2585     blendCompositingSurface(visibleDirtyRect);
2586 #endif
2587 }
2588 #endif
2589
2590 bool BackingStorePrivate::isActive() const
2591 {
2592     return BackingStorePrivate::s_currentBackingStoreOwner == m_webPage && SurfacePool::globalSurfacePool()->isActive();
2593 }
2594
2595 BackingStore::BackingStore(WebPage* webPage, BackingStoreClient* client)
2596     : d(new BackingStorePrivate)
2597 {
2598     d->m_webPage = webPage;
2599     d->m_client = client;
2600 }
2601
2602 BackingStore::~BackingStore()
2603 {
2604     delete d;
2605     d = 0;
2606 }
2607
2608 void BackingStore::createSurface()
2609 {
2610     static bool initialized = false;
2611     if (!initialized) {
2612         BlackBerry::Platform::Graphics::initialize();
2613         initialized = true;
2614     }
2615
2616     // Triggers creation of surfaces in backingstore.
2617     d->createSurfaces();
2618
2619     // Focusing the WebPage triggers a repaint, so while we want it to be
2620     // focused initially this has to happen after creation of the surface.
2621     d->m_webPage->setFocused(true);
2622 }
2623
2624 void BackingStore::suspendScreenAndBackingStoreUpdates()
2625 {
2626     d->suspendScreenAndBackingStoreUpdates();
2627 }
2628
2629 void BackingStore::resumeScreenAndBackingStoreUpdates(ResumeUpdateOperation op)
2630 {
2631     d->resumeScreenAndBackingStoreUpdates(op);
2632 }
2633
2634 bool BackingStore::isScrollingOrZooming() const
2635 {
2636     return d->isScrollingOrZooming();
2637 }
2638
2639 void BackingStore::setScrollingOrZooming(bool scrollingOrZooming)
2640 {
2641     d->setScrollingOrZooming(scrollingOrZooming);
2642 }
2643
2644 void BackingStore::blitContents(const BlackBerry::Platform::IntRect& dstRect, const BlackBerry::Platform::IntRect& contents)
2645 {
2646     // Blitting during direct rendering is not supported.
2647     if (isDirectRenderingToWindow()) {
2648         BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
2649                                "BackingStore::blitContents operation not supported in direct rendering mode");
2650         return;
2651     }
2652
2653     d->blitContents(dstRect, contents);
2654 }
2655
2656 void BackingStore::repaint(int x, int y, int width, int height,
2657                            bool contentChanged, bool immediate)
2658 {
2659     d->repaint(Platform::IntRect(x, y, width, height), contentChanged, immediate);
2660 }
2661
2662 bool BackingStore::hasRenderJobs() const
2663 {
2664     return d->shouldPerformRenderJobs();
2665 }
2666
2667 void BackingStore::renderOnIdle()
2668 {
2669     d->renderOnIdle();
2670 }
2671
2672 bool BackingStore::isDirectRenderingToWindow() const
2673 {
2674     BackingStoreMutexLocker locker(d);
2675     return d->shouldDirectRenderingToWindow();
2676 }
2677
2678 void BackingStore::createBackingStoreMemory()
2679 {
2680     SurfacePool::globalSurfacePool()->createBuffers();
2681 }
2682
2683 void BackingStore::releaseBackingStoreMemory()
2684 {
2685     SurfacePool::globalSurfacePool()->releaseBuffers();
2686 }
2687
2688 bool BackingStore::defersBlit() const
2689 {
2690         return d->m_defersBlit;
2691 }
2692
2693 void BackingStore::setDefersBlit(bool b)
2694 {
2695         d->m_defersBlit = b;
2696 }
2697
2698 bool BackingStore::hasBlitJobs() const
2699 {
2700 #if USE(ACCELERATED_COMPOSITING)
2701     // If there's a WebPageCompositorClient, let it schedule the blit.
2702     WebPageCompositorPrivate* compositor = d->m_webPage->d->compositor();
2703     if (compositor && compositor->client())
2704         return false;
2705 #endif
2706
2707     // Normally, this would be called from the compositing thread,
2708     // and the flag is set on the compositing thread, so no need for
2709     // synchronization.
2710     return d->m_hasBlitJobs;
2711 }
2712
2713 void BackingStore::blitOnIdle()
2714 {
2715 #if USE(ACCELERATED_COMPOSITING)
2716     // If there's a WebPageCompositorClient, let it schedule the blit.
2717     WebPageCompositorPrivate* compositor = d->m_webPage->d->compositor();
2718     if (compositor && compositor->client())
2719         return;
2720 #endif
2721
2722     d->blitVisibleContents(true /*force*/);
2723 }
2724
2725 Platform::IntSize BackingStorePrivate::surfaceSize() const
2726 {
2727     if (Window* window = m_webPage->client()->window())
2728         return window->surfaceSize();
2729
2730 #if USE(ACCELERATED_COMPOSITING)
2731     if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
2732         return compositor->context()->surfaceSize();
2733 #endif
2734
2735     return Platform::IntSize();
2736 }
2737
2738 Platform::Graphics::Buffer* BackingStorePrivate::buffer() const
2739 {
2740     if (Window* window = m_webPage->client()->window())
2741         return window->buffer();
2742
2743 #if USE(ACCELERATED_COMPOSITING)
2744     if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
2745         return compositor->context()->buffer();
2746 #endif
2747
2748     return 0;
2749 }
2750
2751 }
2752 }