#include "config.h"
#include "BackingStore.h"
#include "BackingStoreClient.h"
#include "BackingStoreCompositingSurface.h"
#include "BackingStoreTile.h"
#include "BackingStore_p.h"
#include "FatFingers.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "InspectorController.h"
#include "Page.h"
#include "SurfacePool.h"
#include "WebPage.h"
#include "WebPageClient.h"
#include "WebPageCompositorClient.h"
#include "WebPageCompositor_p.h"
#include "WebPage_p.h"
#include "WebSettings.h"
#include <BlackBerryPlatformClient.h>
#include <BlackBerryPlatformExecutableMessage.h>
#include <BlackBerryPlatformGraphics.h>
#include <BlackBerryPlatformIntRectRegion.h>
#include <BlackBerryPlatformLog.h>
#include <BlackBerryPlatformMessage.h>
#include <BlackBerryPlatformMessageClient.h>
#include <BlackBerryPlatformScreen.h>
#include <BlackBerryPlatformSettings.h>
#include <BlackBerryPlatformWindow.h>
#include <SkImageDecoder.h>
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
#include <wtf/NotFound.h>
#define SUPPRESS_NON_VISIBLE_REGULAR_RENDER_JOBS 0
#define ENABLE_SCROLLBARS 1
#define ENABLE_REPAINTONSCROLL 1
#define DEBUG_BACKINGSTORE 0
#define DEBUG_CHECKERBOARD 0
#define DEBUG_WEBCORE_REQUESTS 0
#define DEBUG_VISUALIZE 0
#define DEBUG_TILEMATRIX 0
#define DEBUG_COMPOSITING_DIRTY_REGION 0
using namespace WebCore;
using namespace std;
using BlackBerry::Platform::Graphics::Window;
using BlackBerry::Platform::IntRect;
using BlackBerry::Platform::IntPoint;
using BlackBerry::Platform::IntSize;
namespace BlackBerry {
namespace WebKit {
const int s_renderTimerTimeout = 1.0;
WebPage* BackingStorePrivate::s_currentBackingStoreOwner = 0;
Platform::Graphics::Buffer* BackingStorePrivate::s_overScrollImage = 0;
std::string BackingStorePrivate::s_overScrollImagePath;
typedef std::pair<int, int> Divisor;
typedef Vector<Divisor> DivisorList;
static DivisorList divisors(unsigned n)
{
DivisorList divisors;
for (unsigned i = 1; i <= n; ++i)
if (!(n % i))
divisors.append(std::make_pair(i, n / i));
return divisors;
}
static bool divisorIsPerfectWidth(Divisor divisor, Platform::IntSize size, int tileWidth)
{
return size.width() <= divisor.first * tileWidth && abs(size.width() - divisor.first * tileWidth) < tileWidth;
}
static bool divisorIsPerfectHeight(Divisor divisor, Platform::IntSize size, int tileHeight)
{
return size.height() <= divisor.second * tileHeight && abs(size.height() - divisor.second * tileHeight) < tileHeight;
}
static bool divisorIsPreferredDirection(Divisor divisor, BackingStorePrivate::TileMatrixDirection direction)
{
if (direction == BackingStorePrivate::Vertical)
return divisor.second > divisor.first;
return divisor.first > divisor.second;
}
static Divisor bestDivisor(Platform::IntSize size, int tileWidth, int tileHeight,
int minimumNumberOfTilesWide, int minimumNumberOfTilesHigh,
BackingStorePrivate::TileMatrixDirection direction)
{
SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
ASSERT(!surfacePool->isEmpty());
static DivisorList divisorList = divisors(surfacePool->size());
float ratio = static_cast<float>(size.width()) / static_cast<float>(size.height());
Divisor bestDivisor;
for (size_t i = 0; i < divisorList.size(); ++i) {
Divisor divisor = divisorList[i];
const bool isPerfectWidth = divisorIsPerfectWidth(divisor, size, tileWidth);
const bool isPerfectHeight = divisorIsPerfectHeight(divisor, size, tileHeight);
const bool isValidWidth = divisor.first >= minimumNumberOfTilesWide || isPerfectWidth;
const bool isValidHeight = divisor.second >= minimumNumberOfTilesHigh || isPerfectHeight;
if (!isValidWidth || !isValidHeight)
continue;
if (isPerfectWidth || isPerfectHeight) {
bestDivisor = divisor; #if DEBUG_TILEMATRIX
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "bestDivisor found perfect size isPerfectWidth=%s isPerfectHeight=%s",
isPerfectWidth ? "true" : "false",
isPerfectHeight ? "true" : "false");
#endif
break;
}
if (!bestDivisor.first || !bestDivisor.second) {
bestDivisor = divisor;
continue;
}
if (divisorIsPreferredDirection(bestDivisor, direction) && !divisorIsPreferredDirection(divisor, direction))
continue;
float diff1 = fabs((static_cast<float>(divisor.first) / static_cast<float>(divisor.second)) - ratio);
float diff2 = fabs((static_cast<float>(bestDivisor.first) / static_cast<float>(bestDivisor.second)) - ratio);
if (diff1 < diff2)
bestDivisor = divisor;
}
return bestDivisor;
}
struct BackingStoreMutexLocker {
BackingStoreMutexLocker(BackingStorePrivate* backingStorePrivate)
: m_backingStorePrivate(backingStorePrivate)
{
m_backingStorePrivate->lockBackingStore();
}
~BackingStoreMutexLocker()
{
m_backingStorePrivate->unlockBackingStore();
}
private:
BackingStorePrivate* m_backingStorePrivate;
};
Platform::IntRect BackingStoreGeometry::backingStoreRect() const
{
return Platform::IntRect(backingStoreOffset(), backingStoreSize());
}
Platform::IntSize BackingStoreGeometry::backingStoreSize() const
{
return Platform::IntSize(numberOfTilesWide() * BackingStorePrivate::tileWidth(), numberOfTilesHigh() * BackingStorePrivate::tileHeight());
}
BackingStorePrivate::BackingStorePrivate()
: m_suspendScreenUpdates(false)
, m_suspendBackingStoreUpdates(false)
, m_suspendRenderJobs(false)
, m_suspendRegularRenderJobs(false)
, m_isScrollingOrZooming(false)
, m_webPage(0)
, m_client(0)
, m_renderQueue(adoptPtr(new RenderQueue(this)))
, m_defersBlit(true)
, m_hasBlitJobs(false)
, m_currentWindowBackBuffer(0)
, m_preferredTileMatrixDimension(Vertical)
, m_blitGeneration(-1)
#if USE(ACCELERATED_COMPOSITING)
, m_needsDrawLayersOnCommit(false)
, m_isDirectRenderingAnimationMessageScheduled(false)
#endif
{
m_frontState = reinterpret_cast<unsigned>(new BackingStoreGeometry);
m_backState = reinterpret_cast<unsigned>(new BackingStoreGeometry);
m_renderTimer = adoptPtr(new Timer<BackingStorePrivate>(this, &BackingStorePrivate::renderOnTimer));
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m_mutex, &attr);
pthread_mutexattr_destroy(&attr);
pthread_mutex_init(&m_blitGenerationLock, 0);
pthread_cond_init(&m_blitGenerationCond, 0);
}
BackingStorePrivate::~BackingStorePrivate()
{
BackingStoreGeometry* front = reinterpret_cast<BackingStoreGeometry*>(m_frontState);
delete front;
m_frontState = 0;
BackingStoreGeometry* back = reinterpret_cast<BackingStoreGeometry*>(m_backState);
delete back;
m_backState = 0;
pthread_cond_destroy(&m_blitGenerationCond);
pthread_mutex_destroy(&m_blitGenerationLock);
pthread_mutex_destroy(&m_mutex);
}
bool BackingStorePrivate::shouldDirectRenderingToWindow() const
{
if (isOpenGLCompositing())
return false;
if (m_webPage->settings()->isDirectRenderingToWindowEnabled())
return true;
if (!isActive())
return !m_webPage->d->compositorDrawsRootLayer();
const BackingStoreGeometry* currentState = frontState();
const unsigned tilesNecessary = minimumNumberOfTilesWide() * minimumNumberOfTilesHigh();
const unsigned tilesAvailable = currentState->numberOfTilesWide() * currentState->numberOfTilesHigh();
return tilesAvailable < tilesNecessary;
}
bool BackingStorePrivate::isOpenGLCompositing() const
{
if (Window* window = m_webPage->client()->window())
return window->windowUsage() == Window::GLES2Usage;
return true;
}
void BackingStorePrivate::suspendScreenAndBackingStoreUpdates()
{
m_suspendBackingStoreUpdates = true;
m_suspendScreenUpdates = true;
BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
#if USE(ACCELERATED_COMPOSITING)
m_webPage->d->resetCompositingSurface();
#endif
}
void BackingStorePrivate::resumeScreenAndBackingStoreUpdates(BackingStore::ResumeUpdateOperation op)
{
m_suspendBackingStoreUpdates = false;
#if USE(ACCELERATED_COMPOSITING)
if (op != BackingStore::None)
m_webPage->d->setNeedsOneShotDrawingSynchronization();
#endif
if (shouldDirectRenderingToWindow() && op == BackingStore::Blit)
op = BackingStore::RenderAndBlit;
if (op == BackingStore::RenderAndBlit)
renderVisibleContents();
m_suspendScreenUpdates = false;
BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
if ((op == BackingStore::Blit || op == BackingStore::RenderAndBlit) && !shouldDirectRenderingToWindow())
blitVisibleContents();
}
void BackingStorePrivate::repaint(const Platform::IntRect& windowRect,
bool contentChanged, bool immediate)
{
if (m_suspendBackingStoreUpdates)
return;
if (contentChanged && !windowRect.isEmpty()) {
Platform::IntRect rect = m_webPage->d->mapToTransformed(m_client->mapFromViewportToContents(windowRect));
rect.inflate(1 , 1 );
WebCore::IntRect tmpRect = rect;
m_client->clipToTransformedContentsRect(tmpRect);
rect = tmpRect;
if (rect.isEmpty())
return;
#if DEBUG_WEBCORE_REQUESTS
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"BackingStorePrivate::repaint rect=%d,%d %dx%d contentChanged=%s immediate=%s",
rect.x(), rect.y(), rect.width(), rect.height(),
(contentChanged ? "true" : "false"),
(immediate ? "true" : "false"));
#endif
if (immediate) {
if (render(rect) && !shouldDirectRenderingToWindow())
blitVisibleContents();
} else
m_renderQueue->addToQueue(RenderQueue::RegularRender, rect);
}
}
void BackingStorePrivate::slowScroll(const Platform::IntSize& delta, const Platform::IntRect& windowRect, bool immediate)
{
#if DEBUG_BACKINGSTORE
double time = WTF::currentTime();
#endif
scrollingStartedHelper(delta);
Platform::IntRect rect = m_webPage->d->mapToTransformed(m_client->mapFromViewportToContents(windowRect));
if (immediate) {
if (render(rect) && !isSuspended() && !shouldDirectRenderingToWindow())
blitVisibleContents();
} else {
m_renderQueue->addToQueue(RenderQueue::VisibleScroll, rect);
if (!m_client->isClientGeneratedScroll() && !shouldDirectRenderingToWindow())
blitVisibleContents();
}
#if DEBUG_BACKINGSTORE
double elapsed = WTF::currentTime() - time;
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::slowScroll elapsed=%f", elapsed);
#endif
}
void BackingStorePrivate::scroll(const Platform::IntSize& delta,
const Platform::IntRect& scrollViewRect,
const Platform::IntRect& clipRect)
{
if (shouldDirectRenderingToWindow()) {
Platform::IntRect viewportRect(Platform::IntPoint(0, 0), m_webPage->d->transformedViewportSize());
slowScroll(delta, m_webPage->d->mapFromTransformed(viewportRect), true );
return;
}
#if DEBUG_BACKINGSTORE
double time = WTF::currentTime();
#endif
scrollingStartedHelper(delta);
if (!m_client->isClientGeneratedScroll())
blitVisibleContents();
#if DEBUG_BACKINGSTORE
double elapsed = WTF::currentTime() - time;
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::scroll dx=%d, dy=%d elapsed=%f", delta.width(), delta.height(), elapsed);
#endif
}
void BackingStorePrivate::scrollingStartedHelper(const Platform::IntSize& delta)
{
m_renderQueue->updateSortDirection(delta.width(), delta.height());
m_renderQueue->visibleContentChanged(visibleContentsRect());
scrollBackingStore(delta.width(), delta.height());
updateTilesForScrollOrNotRenderedRegion();
}
bool BackingStorePrivate::shouldSuppressNonVisibleRegularRenderJobs() const
{
#if SUPPRESS_NON_VISIBLE_REGULAR_RENDER_JOBS
return true;
#else
return m_client->isLoading();
#endif
}
bool BackingStorePrivate::shouldPerformRenderJobs() const
{
return (m_webPage->isVisible() || shouldDirectRenderingToWindow()) && !m_suspendRenderJobs && !m_suspendBackingStoreUpdates && !m_renderQueue->isEmpty(!m_suspendRegularRenderJobs);
}
bool BackingStorePrivate::shouldPerformRegularRenderJobs() const
{
return shouldPerformRenderJobs() && !m_suspendRegularRenderJobs;
}
void BackingStorePrivate::startRenderTimer()
{
if (m_renderTimer->isActive() || m_renderQueue->isEmpty(!m_suspendRegularRenderJobs))
return;
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::startRenderTimer time=%f", WTF::currentTime());
#endif
m_renderTimer->startOneShot(s_renderTimerTimeout);
}
void BackingStorePrivate::stopRenderTimer()
{
if (!m_renderTimer->isActive())
return;
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::stopRenderTimer time=%f", WTF::currentTime());
#endif
m_renderTimer->stop();
}
void BackingStorePrivate::renderOnTimer(WebCore::Timer<BackingStorePrivate>*)
{
if (!shouldPerformRenderJobs())
return;
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::renderOnTimer time=%f", WTF::currentTime());
#endif
while (m_renderQueue->hasCurrentVisibleZoomJob() || m_renderQueue->hasCurrentVisibleScrollJob())
m_renderQueue->render(!m_suspendRegularRenderJobs);
if (shouldPerformRegularRenderJobs() && m_renderQueue->hasCurrentRegularRenderJob())
m_renderQueue->renderAllCurrentRegularRenderJobs();
#if USE(ACCELERATED_COMPOSITING)
drawLayersOnCommitIfNeeded();
#endif
}
void BackingStorePrivate::renderOnIdle()
{
ASSERT(shouldPerformRenderJobs());
m_renderQueue->eventQueueCycled();
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::renderOnIdle");
#endif
m_renderQueue->render(!m_suspendRegularRenderJobs);
#if USE(ACCELERATED_COMPOSITING)
drawLayersOnCommitIfNeeded();
#endif
}
bool BackingStorePrivate::willFireTimer()
{
m_renderQueue->eventQueueCycled();
if (!shouldPerformRegularRenderJobs() || !m_renderQueue->hasCurrentRegularRenderJob() || !m_renderQueue->currentRegularRenderJobBatchUnderPressure())
return true;
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::willFireTimer");
#endif
while (m_renderQueue->hasCurrentVisibleZoomJob() || m_renderQueue->hasCurrentVisibleScrollJob())
m_renderQueue->render(!m_suspendRegularRenderJobs);
if (m_renderQueue->hasCurrentRegularRenderJob())
m_renderQueue->renderAllCurrentRegularRenderJobs();
#if USE(ACCELERATED_COMPOSITING)
drawLayersOnCommitIfNeeded();
#endif
return false;
}
Platform::IntRect BackingStorePrivate::expandedContentsRect() const
{
return Platform::IntRect(Platform::IntPoint(0, 0), expandedContentsSize());
}
Platform::IntRect BackingStorePrivate::visibleContentsRect() const
{
return intersection(m_client->transformedVisibleContentsRect(),
Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedContentsSize()));
}
Platform::IntRect BackingStorePrivate::unclippedVisibleContentsRect() const
{
return m_client->transformedVisibleContentsRect();
}
bool BackingStorePrivate::shouldMoveLeft(const Platform::IntRect& backingStoreRect) const
{
return canMoveX(backingStoreRect)
&& backingStoreRect.x() > visibleContentsRect().x()
&& backingStoreRect.x() > expandedContentsRect().x();
}
bool BackingStorePrivate::shouldMoveRight(const Platform::IntRect& backingStoreRect) const
{
return canMoveX(backingStoreRect)
&& backingStoreRect.right() < visibleContentsRect().right()
&& backingStoreRect.right() < expandedContentsRect().right();
}
bool BackingStorePrivate::shouldMoveUp(const Platform::IntRect& backingStoreRect) const
{
return canMoveY(backingStoreRect)
&& backingStoreRect.y() > visibleContentsRect().y()
&& backingStoreRect.y() > expandedContentsRect().y();
}
bool BackingStorePrivate::shouldMoveDown(const Platform::IntRect& backingStoreRect) const
{
return canMoveY(backingStoreRect)
&& backingStoreRect.bottom() < visibleContentsRect().bottom()
&& backingStoreRect.bottom() < expandedContentsRect().bottom();
}
bool BackingStorePrivate::canMoveX(const Platform::IntRect& backingStoreRect) const
{
return backingStoreRect.width() > visibleContentsRect().width();
}
bool BackingStorePrivate::canMoveY(const Platform::IntRect& backingStoreRect) const
{
return backingStoreRect.height() > visibleContentsRect().height();
}
bool BackingStorePrivate::canMoveLeft(const Platform::IntRect& rect) const
{
Platform::IntRect backingStoreRect = rect;
Platform::IntRect visibleContentsRect = this->visibleContentsRect();
Platform::IntRect contentsRect = this->expandedContentsRect();
backingStoreRect.move(-tileWidth(), 0);
return backingStoreRect.right() >= visibleContentsRect.right()
&& backingStoreRect.x() >= contentsRect.x();
}
bool BackingStorePrivate::canMoveRight(const Platform::IntRect& rect) const
{
Platform::IntRect backingStoreRect = rect;
Platform::IntRect visibleContentsRect = this->visibleContentsRect();
Platform::IntRect contentsRect = this->expandedContentsRect();
backingStoreRect.move(tileWidth(), 0);
return backingStoreRect.x() <= visibleContentsRect.x()
&& (backingStoreRect.right() <= contentsRect.right()
|| (backingStoreRect.right() - contentsRect.right()) < tileWidth());
}
bool BackingStorePrivate::canMoveUp(const Platform::IntRect& rect) const
{
Platform::IntRect backingStoreRect = rect;
Platform::IntRect visibleContentsRect = this->visibleContentsRect();
Platform::IntRect contentsRect = this->expandedContentsRect();
backingStoreRect.move(0, -tileHeight());
return backingStoreRect.bottom() >= visibleContentsRect.bottom()
&& backingStoreRect.y() >= contentsRect.y();
}
bool BackingStorePrivate::canMoveDown(const Platform::IntRect& rect) const
{
Platform::IntRect backingStoreRect = rect;
Platform::IntRect visibleContentsRect = this->visibleContentsRect();
Platform::IntRect contentsRect = this->expandedContentsRect();
backingStoreRect.move(0, tileHeight());
return backingStoreRect.y() <= visibleContentsRect.y()
&& (backingStoreRect.bottom() <= contentsRect.bottom()
|| (backingStoreRect.bottom() - contentsRect.bottom()) < tileHeight());
}
Platform::IntRect BackingStorePrivate::backingStoreRectForScroll(int deltaX, int deltaY, const Platform::IntRect& rect) const
{
Platform::IntRect backingStoreRect = rect;
if (!deltaX && !deltaY) {
deltaX = m_previousDelta.width();
deltaY = m_previousDelta.height();
}
m_previousDelta = Platform::IntSize(deltaX, deltaY);
if (!canMoveX(backingStoreRect) && backingStoreRect.x())
backingStoreRect.setX(0);
if (!canMoveY(backingStoreRect) && backingStoreRect.y())
backingStoreRect.setY(0);
while (shouldMoveLeft(backingStoreRect) || (deltaX > 0 && canMoveLeft(backingStoreRect)))
backingStoreRect.move(-tileWidth(), 0);
while (shouldMoveRight(backingStoreRect) || (deltaX < 0 && canMoveRight(backingStoreRect)))
backingStoreRect.move(tileWidth(), 0);
while (shouldMoveUp(backingStoreRect) || (deltaY > 0 && canMoveUp(backingStoreRect)))
backingStoreRect.move(0, -tileHeight());
while (shouldMoveDown(backingStoreRect) || (deltaY < 0 && canMoveDown(backingStoreRect)))
backingStoreRect.move(0, tileHeight());
return backingStoreRect;
}
void BackingStorePrivate::setBackingStoreRect(const Platform::IntRect& backingStoreRect)
{
if (!m_webPage->isVisible())
return;
if (!isActive()) {
m_webPage->d->setShouldResetTilesWhenShown(true);
return;
}
Platform::IntRect currentBackingStoreRect = frontState()->backingStoreRect();
if (backingStoreRect == currentBackingStoreRect)
return;
#if DEBUG_TILEMATRIX
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::setBackingStoreRect changed from (%d,%d %dx%d) to (%d,%d %dx%d)",
currentBackingStoreRect.x(),
currentBackingStoreRect.y(),
currentBackingStoreRect.width(),
currentBackingStoreRect.height(),
backingStoreRect.x(),
backingStoreRect.y(),
backingStoreRect.width(),
backingStoreRect.height());
#endif
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
TileIndexList indexesToFill = indexesForBackingStoreRect(backingStoreRect);
ASSERT(static_cast<int>(indexesToFill.size()) == currentMap.size());
TileMap newTileMap;
TileMap leftOverTiles;
TileMap::const_iterator tileMapEnd = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != tileMapEnd; ++it) {
TileIndex oldIndex = it->first;
BackingStoreTile* tile = it->second;
resetTile(oldIndex, tile, false );
Platform::IntPoint origin = originOfLastRenderForTile(oldIndex, tile, currentBackingStoreRect);
if (backingStoreRect.contains(origin)) {
TileIndex newIndex = indexOfTile(origin, backingStoreRect);
Platform::IntRect rect(origin, tileSize());
if (m_renderQueue->regularRenderJobsPreviouslyAttemptedButNotRendered(rect)) {
Platform::IntRectRegion tileNotRenderedRegion = Platform::IntRectRegion::intersectRegions(m_renderQueue->regularRenderJobsNotRenderedRegion(), rect);
clearAndUpdateTileOfNotRenderedRegion(newIndex, tile, tileNotRenderedRegion, backingStoreRect);
#if DEBUG_BACKINGSTORE
Platform::IntRect extents = tileNotRenderedRegion.extents();
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::setBackingStoreRect did clear tile %d,%d %dx%d",
extents.x(), extents.y(), extents.width(), extents.height());
#endif
} else {
if (!tile->frontBuffer()->isRendered()
&& !isCurrentVisibleJob(newIndex, tile, backingStoreRect))
updateTile(origin, false );
}
tile->clearShift();
tile->setCommitted(true);
size_t i = indexesToFill.find(newIndex);
ASSERT(i != WTF::notFound);
indexesToFill.remove(i);
newTileMap.add(newIndex, tile);
} else {
leftOverTiles.add(oldIndex, tile);
}
}
ASSERT(static_cast<int>(indexesToFill.size()) == leftOverTiles.size());
size_t i = 0;
TileMap::const_iterator leftOverEnd = leftOverTiles.end();
for (TileMap::const_iterator it = leftOverTiles.begin(); it != leftOverEnd; ++it) {
TileIndex oldIndex = it->first;
BackingStoreTile* tile = it->second;
if (i >= indexesToFill.size()) {
ASSERT_NOT_REACHED();
break;
}
TileIndex newIndex = indexesToFill.at(i);
Platform::IntPoint originOfOld = originOfLastRenderForTile(oldIndex, tile, currentBackingStoreRect);
Platform::IntPoint originOfNew = originOfTile(newIndex, backingStoreRect);
updateTile(originOfNew, false );
tile->clearShift();
tile->setCommitted(false);
tile->setHorizontalShift((originOfOld.x() - originOfNew.x()) / tileWidth());
tile->setVerticalShift((originOfOld.y() - originOfNew.y()) / tileHeight());
newTileMap.add(newIndex, tile);
++i;
}
ASSERT(currentMap.size() == newTileMap.size());
backState()->setNumberOfTilesWide(backingStoreRect.width() / tileWidth());
backState()->setNumberOfTilesHigh(backingStoreRect.height() / tileHeight());
backState()->setBackingStoreOffset(backingStoreRect.location());
backState()->setTileMap(newTileMap);
swapState();
}
BackingStorePrivate::TileIndexList BackingStorePrivate::indexesForBackingStoreRect(const Platform::IntRect& backingStoreRect) const
{
TileIndexList indexes;
int numberOfTilesWide = backingStoreRect.width() / tileWidth();
int numberOfTilesHigh = backingStoreRect.height() / tileHeight();
for (int y = 0; y < numberOfTilesHigh; ++y) {
for (int x = 0; x < numberOfTilesWide; ++x) {
TileIndex index(x, y);
indexes.append(index);
}
}
return indexes;
}
Platform::IntPoint BackingStorePrivate::originOfLastRenderForTile(const TileIndex& index,
BackingStoreTile* tile,
const Platform::IntRect& backingStoreRect) const
{
return originOfTile(indexOfLastRenderForTile(index, tile), backingStoreRect);
}
TileIndex BackingStorePrivate::indexOfLastRenderForTile(const TileIndex& index, BackingStoreTile* tile) const
{
return TileIndex(index.i() + tile->horizontalShift(), index.j() + tile->verticalShift());
}
TileIndex BackingStorePrivate::indexOfTile(const Platform::IntPoint& origin,
const Platform::IntRect& backingStoreRect) const
{
int offsetX = origin.x() - backingStoreRect.x();
int offsetY = origin.y() - backingStoreRect.y();
if (offsetX)
offsetX = offsetX / tileWidth();
if (offsetY)
offsetY = offsetY / tileHeight();
return TileIndex(offsetX, offsetY);
}
void BackingStorePrivate::clearAndUpdateTileOfNotRenderedRegion(const TileIndex& index, BackingStoreTile* tile,
const Platform::IntRectRegion& tileNotRenderedRegion,
const Platform::IntRect& backingStoreRect,
bool update)
{
IntRectList tileNotRenderedRegionRects = tileNotRenderedRegion.rects();
for (size_t i = 0; i < tileNotRenderedRegionRects.size(); ++i) {
Platform::IntRect tileNotRenderedRegionRect = tileNotRenderedRegionRects.at(i);
m_renderQueue->clear(tileNotRenderedRegionRect, true );
if (update) {
m_renderQueue->addToQueue(RenderQueue::RegularRender, tileNotRenderedRegionRect);
}
Platform::IntPoint origin = originOfTile(index, backingStoreRect);
tileNotRenderedRegionRect.move(-origin.x(), -origin.y());
tile->frontBuffer()->clearRenderedRegion(tileNotRenderedRegionRect);
tile->backBuffer()->clearRenderedRegion(tileNotRenderedRegionRect);
}
}
bool BackingStorePrivate::isCurrentVisibleJob(const TileIndex& index, BackingStoreTile* tile, const Platform::IntRect& backingStoreRect) const
{
Platform::IntRect wholeRect = Platform::IntRect(originOfTile(index, backingStoreRect), tileSize());
if (m_renderQueue->isCurrentVisibleScrollJob(wholeRect) || m_renderQueue->isCurrentVisibleScrollJobCompleted(wholeRect))
return true;
bool isCurrent = true;
IntRectList tileNotRenderedRegionRects = tile->frontBuffer()->notRenderedRegion().rects();
for (size_t i = 0; i < tileNotRenderedRegionRects.size(); ++i) {
Platform::IntRect tileNotRenderedRegionRect = tileNotRenderedRegionRects.at(i);
Platform::IntPoint origin = originOfTile(index, backingStoreRect);
tileNotRenderedRegionRect.move(origin.x(), origin.y());
isCurrent = m_renderQueue->isCurrentRegularRenderJob(tileNotRenderedRegionRect) ? isCurrent : false;
}
return isCurrent;
}
void BackingStorePrivate::scrollBackingStore(int deltaX, int deltaY)
{
if (!m_webPage->isVisible())
return;
if (!isActive()) {
m_webPage->d->setShouldResetTilesWhenShown(true);
return;
}
if (deltaX || deltaY)
m_preferredTileMatrixDimension = abs(deltaX) > abs(deltaY) ? Horizontal : Vertical;
Divisor divisor = bestDivisor(expandedContentsSize(),
tileWidth(), tileHeight(),
minimumNumberOfTilesWide(), minimumNumberOfTilesHigh(),
m_preferredTileMatrixDimension);
#if DEBUG_TILEMATRIX
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::scrollBackingStore divisor %dx%d",
divisor.first,
divisor.second);
#endif
Platform::IntRect backingStoreRect(0, 0, divisor.first * tileWidth(), divisor.second * tileHeight());
backingStoreRect = backingStoreRectForScroll(deltaX, deltaY, backingStoreRect);
ASSERT(!backingStoreRect.isEmpty());
setBackingStoreRect(backingStoreRect);
}
bool BackingStorePrivate::renderDirectToWindow(const Platform::IntRect& rect)
{
requestLayoutIfNeeded();
Platform::IntRect dirtyRect = rect;
dirtyRect.intersect(unclippedVisibleContentsRect());
if (dirtyRect.isEmpty())
return false;
Platform::IntRect screenRect = m_client->mapFromTransformedContentsToTransformedViewport(dirtyRect);
windowFrontBufferState()->clearBlittedRegion(screenRect);
paintDefaultBackground(dirtyRect, TransformationMatrix(), true );
const Platform::IntPoint origin = unclippedVisibleContentsRect().location();
renderContents(0, origin, dirtyRect);
windowBackBufferState()->addBlittedRegion(screenRect);
#if USE(ACCELERATED_COMPOSITING)
m_isDirectRenderingAnimationMessageScheduled = false;
if (m_webPage->d->isAcceleratedCompositingActive()) {
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
BlackBerry::Platform::createMethodCallMessage(
&BackingStorePrivate::drawAndBlendLayersForDirectRendering,
this, dirtyRect));
}
#endif
invalidateWindow(screenRect);
return true;
}
bool BackingStorePrivate::render(const Platform::IntRect& rect)
{
if (!m_webPage->isVisible())
return false;
requestLayoutIfNeeded();
if (shouldDirectRenderingToWindow())
return renderDirectToWindow(rect);
TileRectList tileRectList = mapFromTransformedContentsToTiles(rect);
if (tileRectList.isEmpty())
return false;
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"BackingStorePrivate::render rect=(%d,%d %dx%d), m_suspendBackingStoreUpdates = %s",
rect.x(), rect.y(), rect.width(), rect.height(),
m_suspendBackingStoreUpdates ? "true" : "false");
#endif
bool blittingDirectlyToCompositingWindow = isOpenGLCompositing();
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
Platform::IntRect dirtyContentsRect;
for (size_t i = 0; i < tileRectList.size(); ++i) {
TileRect tileRect = tileRectList[i];
TileIndex index = tileRect.first;
Platform::IntRect dirtyTileRect = tileRect.second;
BackingStoreTile* tile = currentMap.get(index);
Platform::IntRect dirtyRect = mapFromTilesToTransformedContents(tileRect);
if (!tile->isCommitted()) {
tile->setCommitted(true);
tile->frontBuffer()->clearRenderedRegion();
tile->backBuffer()->clearRenderedRegion();
tile->clearShift();
}
if (!tile->backgroundPainted())
tile->paintBackground();
if (!expandedContentsRect().isEmpty()) {
dirtyRect.intersect(expandedContentsRect());
dirtyTileRect.intersect(tileContentsRect(index, expandedContentsRect(), currentState));
if (dirtyRect.isEmpty())
continue;
}
copyPreviousContentsToBackSurfaceOfTile(dirtyTileRect, tile);
BlackBerry::Platform::Graphics::Buffer* nativeBuffer
= tile->backBuffer()->nativeBuffer();
if (blittingDirectlyToCompositingWindow) {
pthread_mutex_lock(&m_blitGenerationLock);
while (m_blitGeneration == tile->backBuffer()->blitGeneration()) {
int err = pthread_cond_timedwait(&m_blitGenerationCond, &m_blitGenerationLock, &m_currentBlitEnd);
if (err == ETIMEDOUT) {
++m_blitGeneration;
break;
}
if (err) {
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"cond_timedwait failed (%s)", strerror(err));
break;
}
}
pthread_mutex_unlock(&m_blitGenerationLock);
}
renderContents(nativeBuffer, originOfTile(index), dirtyRect);
tile->backBuffer()->addRenderedRegion(dirtyTileRect);
bool backBufferIsValid = tile->backBuffer()->isRendered(tile->frontBuffer()->renderedRegion());
ASSERT(backBufferIsValid);
if (backBufferIsValid) {
tile->swapBuffers();
BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
tile->backBuffer()->clearRenderedRegion();
}
dirtyContentsRect = Platform::unionOfRects(dirtyContentsRect, dirtyRect);
}
return true;
}
void BackingStorePrivate::requestLayoutIfNeeded() const
{
m_webPage->d->requestLayoutIfNeeded();
}
bool BackingStorePrivate::renderVisibleContents()
{
Platform::IntRect renderRect = shouldDirectRenderingToWindow() ? visibleContentsRect() : visibleTilesRect();
if (render(renderRect)) {
m_renderQueue->clear(renderRect, true );
return true;
}
return false;
}
bool BackingStorePrivate::renderBackingStore()
{
return render(frontState()->backingStoreRect());
}
void BackingStorePrivate::blitVisibleContents(bool force)
{
ASSERT(!shouldDirectRenderingToWindow());
if (shouldDirectRenderingToWindow())
return;
if (m_suspendScreenUpdates) {
if (force)
m_hasBlitJobs = false;
return;
}
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
#if USE(ACCELERATED_COMPOSITING)
m_needsDrawLayersOnCommit = false;
#endif
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
BlackBerry::Platform::createMethodCallMessage(
&BackingStorePrivate::blitVisibleContents, this, force));
return;
}
blitContents(m_webPage->client()->userInterfaceBlittedDestinationRect(),
m_webPage->client()->userInterfaceBlittedVisibleContentsRect(),
force);
}
void BackingStorePrivate::copyPreviousContentsToBackSurfaceOfWindow()
{
Platform::IntRectRegion previousContentsRegion
= Platform::IntRectRegion::subtractRegions(windowFrontBufferState()->blittedRegion(), windowBackBufferState()->blittedRegion());
if (previousContentsRegion.isEmpty())
return;
if (Window* window = m_webPage->client()->window())
window->copyFromFrontToBack(previousContentsRegion);
windowBackBufferState()->addBlittedRegion(previousContentsRegion);
}
void BackingStorePrivate::copyPreviousContentsToBackSurfaceOfTile(const Platform::IntRect& rect,
BackingStoreTile* tile)
{
Platform::IntRectRegion previousContentsRegion
= Platform::IntRectRegion::subtractRegions(tile->frontBuffer()->renderedRegion(), rect);
IntRectList previousContentsRects = previousContentsRegion.rects();
for (size_t i = 0; i < previousContentsRects.size(); ++i) {
Platform::IntRect previousContentsRect = previousContentsRects.at(i);
tile->backBuffer()->addRenderedRegion(previousContentsRect);
BlackBerry::Platform::Graphics::blitToBuffer(
tile->backBuffer()->nativeBuffer(), previousContentsRect,
tile->frontBuffer()->nativeBuffer(), previousContentsRect);
}
}
bool BackingStorePrivate::ensureOverScrollImage()
{
std::string path = m_webPage->settings()->overScrollImagePath().utf8();
if (path == "")
return false;
if (s_overScrollImage && path == s_overScrollImagePath)
return true;
std::string imagePath = Platform::Client::get()->getApplicationDirectory() + path;
SkBitmap bitmap;
if (!SkImageDecoder::DecodeFile(imagePath.c_str(), &bitmap)) {
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"BackingStorePrivate::ensureOverScrollImage could not decode overscroll image: %s", imagePath.c_str());
return false;
}
if (bitmap.width() != surfaceSize().width() || bitmap.height() != surfaceSize().height())
return false;
s_overScrollImage = createBuffer(Platform::IntSize(bitmap.width(), bitmap.height()), Platform::Graphics::TemporaryBuffer);
SkCanvas* canvas = Platform::Graphics::lockBufferDrawable(s_overScrollImage);
if (!canvas) {
destroyBuffer(s_overScrollImage);
s_overScrollImage = 0;
return false;
}
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
paint.setFlags(SkPaint::kAntiAlias_Flag);
paint.setFilterBitmap(true);
SkRect rect = SkRect::MakeXYWH(0, 0, bitmap.width(), bitmap.height());
canvas->save();
canvas->drawBitmapRect(bitmap, 0, rect, &paint);
canvas->restore();
Platform::Graphics::releaseBufferDrawable(s_overScrollImage);
s_overScrollImagePath = path;
return true;
}
void BackingStorePrivate::paintDefaultBackground(const Platform::IntRect& contents,
const WebCore::TransformationMatrix& transformation,
bool flush)
{
const Platform::IntRect contentsRect = Platform::IntRect(Platform::IntPoint(0, 0), m_webPage->d->transformedContentsSize());
Platform::IntPoint origin = contents.location();
Platform::IntRect contentsClipped = contents;
Color color(m_webPage->settings()->overZoomColor());
Platform::IntRectRegion overScrollRegion
= Platform::IntRectRegion::subtractRegions(Platform::IntRect(contentsClipped), contentsRect);
IntRectList overScrollRects = overScrollRegion.rects();
for (size_t i = 0; i < overScrollRects.size(); ++i) {
Platform::IntRect overScrollRect = overScrollRects.at(i);
overScrollRect.move(-origin.x(), -origin.y());
overScrollRect = transformation.mapRect(overScrollRect);
if (!transformation.isIdentity()) {
overScrollRect.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
}
if (ensureOverScrollImage())
blitToWindow(overScrollRect, s_overScrollImage, overScrollRect, false, 255);
else
clearWindow(overScrollRect, color.red(), color.green(), color.blue(), color.alpha());
}
}
void BackingStorePrivate::blitContents(const Platform::IntRect& dstRect,
const Platform::IntRect& srcRect,
bool force)
{
ASSERT(!shouldDirectRenderingToWindow());
if (shouldDirectRenderingToWindow())
return;
if (!m_webPage->isVisible() || m_suspendScreenUpdates) {
if (force)
m_hasBlitJobs = false;
return;
}
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
#if USE(ACCELERATED_COMPOSITING)
m_needsDrawLayersOnCommit = false;
#endif
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
BlackBerry::Platform::createMethodCallMessage(
&BackingStorePrivate::blitContents, this, dstRect, srcRect, force));
return;
}
if (m_defersBlit && !force) {
#if USE(ACCELERATED_COMPOSITING)
if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor()) {
if (WebPageCompositorClient* client = compositor->client()) {
client->invalidate(0);
return;
}
}
#endif
m_hasBlitJobs = true;
return;
}
m_hasBlitJobs = false;
const Platform::IntRect contentsRect = Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedContentsSize());
#if DEBUG_VISUALIZE
WebCore::IntRect debugRect = frontState()->backingStoreRect();
debugRect.unite(m_webPage->client()->userInterfaceBlittedVisibleContentsRect());
if (debugRect.width() < debugRect.height())
debugRect.setWidth(ceil(double(srcRect.width()) * (double(debugRect.height()) / srcRect.height())));
if (debugRect.height() < debugRect.width())
debugRect.setHeight(ceil(double(srcRect.height()) * (double(debugRect.width()) / srcRect.width())));
Platform::IntRect contents = debugRect;
#else
Platform::IntRect contents = srcRect;
#endif
TransformationMatrix transformation;
if (!contents.isEmpty())
transformation = TransformationMatrix::rectToRect(FloatRect(FloatPoint(0.0, 0.0), WebCore::IntSize(contents.size())), WebCore::IntRect(dstRect));
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"BackingStorePrivate::blitContents dstRect=(%d,%d %dx%d) srcRect=(%d,%d %dx%d)",
dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(),
srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
#endif
Platform::IntPoint origin = contents.location();
Platform::IntRect contentsClipped = contents;
Vector<TileBuffer*> blittedTiles;
if (isActive() && !m_webPage->d->compositorDrawsRootLayer()) {
paintDefaultBackground(contents, transformation, false );
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
#if DEBUG_CHECKERBOARD
bool blitCheckered = false;
#endif
if (!contentsRect.isEmpty()) {
contentsClipped.intersect(contentsRect);
if (contentsClipped.isEmpty()) {
invalidateWindow(dstRect);
return;
}
Platform::IntRectRegion contentsRegion = contentsClipped;
Platform::IntRectRegion backingStoreRegion = currentState->backingStoreRect();
Platform::IntRectRegion checkeredRegion
= Platform::IntRectRegion::subtractRegions(contentsRegion, backingStoreRegion);
IntRectList checkeredRects = checkeredRegion.rects();
for (size_t i = 0; i < checkeredRects.size(); ++i) {
Platform::IntRect dstRect = transformation.mapRect(Platform::IntRect(
Platform::IntPoint(checkeredRects.at(i).x() - origin.x(), checkeredRects.at(i).y() - origin.y()),
checkeredRects.at(i).size()));
#if DEBUG_CHECKERBOARD
blitCheckered = true;
#endif
checkerWindow(dstRect, checkeredRects.at(i).location(), transformation.a());
}
}
TileRectList tileRectList = mapFromTransformedContentsToTiles(contentsClipped, currentState);
for (size_t i = 0; i < tileRectList.size(); ++i) {
TileRect tileRect = tileRectList[i];
TileIndex index = tileRect.first;
Platform::IntRect dirtyTileRect = tileRect.second;
BackingStoreTile* tile = currentMap.get(index);
TileBuffer* tileBuffer = tile->frontBuffer();
Platform::IntRect dirtyRect
= mapFromTilesToTransformedContents(tileRect, currentState->backingStoreRect());
if (!contentsRect.isEmpty()) {
dirtyRect.intersect(contentsRect);
if (dirtyRect.isEmpty())
continue;
}
dirtyRect.move(-origin.x(), -origin.y());
if (dirtyRect.isEmpty() || dirtyTileRect.isEmpty())
continue;
TileRect wholeTileRect;
wholeTileRect.first = index;
wholeTileRect.second = this->tileRect();
bool committed = tile->isCommitted();
bool rendered = tileBuffer->isRendered(dirtyTileRect);
bool paintCheckered = !committed || !rendered;
if (paintCheckered) {
Platform::IntRect dirtyRectT = transformation.mapRect(dirtyRect);
if (!transformation.isIdentity()) {
dirtyRectT.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
}
const Platform::IntPoint contentsOrigin(dirtyRect.x() + origin.x(), dirtyRect.y() + origin.y());
#if DEBUG_CHECKERBOARD
blitCheckered = true;
#endif
checkerWindow(dirtyRectT, contentsOrigin, transformation.a());
}
if (m_renderQueue->hasCurrentVisibleZoomJob()) {
Platform::IntRect visibleTileBufferRect = m_visibleTileBufferRect;
visibleTileBufferRect.move(-origin.x(), -origin.y());
dirtyRect.intersect(visibleTileBufferRect);
visibleTileBufferRect.intersect(dirtyRect);
if (!dirtyRect.isEmpty() && !visibleTileBufferRect.isEmpty()) {
BackingStoreTile* visibleTileBuffer
= SurfacePool::globalSurfacePool()->visibleTileBuffer();
ASSERT(visibleTileBuffer->size() == visibleContentsRect().size());
Platform::IntPoint difference = origin - m_visibleTileBufferRect.location();
Platform::IntSize offset = Platform::IntSize(difference.x(), difference.y());
Platform::IntRect dirtyTileRect = visibleTileBufferRect;
dirtyTileRect.move(offset.width(), offset.height());
Platform::IntRect dirtyRectT = transformation.mapRect(dirtyRect);
if (!transformation.isIdentity()) {
dirtyRectT.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
}
blitToWindow(dirtyRectT,
visibleTileBuffer->frontBuffer()->nativeBuffer(),
dirtyTileRect,
false , 255);
}
} else if (committed) {
Platform::IntRectRegion renderedRegion = tileBuffer->renderedRegion();
IntRectList dirtyRenderedRects = renderedRegion.rects();
for (size_t i = 0; i < dirtyRenderedRects.size(); ++i) {
TileRect tileRect;
tileRect.first = index;
tileRect.second = intersection(dirtyTileRect, dirtyRenderedRects.at(i));
if (tileRect.second.isEmpty())
continue;
blitTileRect(tileBuffer, tileRect, origin, transformation, currentState);
}
blittedTiles.append(tileBuffer);
}
}
}
bool blittingDirectlyToCompositingWindow = isOpenGLCompositing();
#if USE(ACCELERATED_COMPOSITING)
if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor()) {
WebCore::FloatRect contentsRect = m_webPage->d->mapFromTransformedFloatRect(WebCore::FloatRect(WebCore::IntRect(contents)));
compositor->drawLayers(dstRect, contentsRect);
if (compositor->drawsRootLayer())
paintDefaultBackground(contents, transformation, false );
}
if (!blittingDirectlyToCompositingWindow)
blendCompositingSurface(dstRect);
#endif
#if ENABLE_SCROLLBARS
if (isScrollingOrZooming() && m_client->isMainFrame()) {
if (m_client->scrollsHorizontally())
blitHorizontalScrollbar(origin);
if (m_client->scrollsVertically())
blitVerticalScrollbar(origin);
}
#endif
#if DEBUG_VISUALIZE
BlackBerry::Platform::Graphics::Buffer* windowBuffer = buffer();
BlackBerry::Platform::Graphics::Drawable* bufferDrawable =
BlackBerry::Platform::Graphics::lockBufferDrawable(windowBuffer);
PlatformGraphicsContext* bufferPlatformGraphicsContext =
SurfacePool::globalSurfacePool()->createPlatformGraphicsContext(bufferDrawable);
GraphicsContext graphicsContext(bufferPlatformGraphicsContext);
FloatRect wkViewport = FloatRect(visibleContentsRect());
FloatRect uiViewport = FloatRect(m_webPage->client()->userInterfaceBlittedVisibleContentsRect());
wkViewport.move(-contents.x(), -contents.y());
uiViewport.move(-contents.x(), -contents.y());
graphicsContext.save();
graphicsContext.setStrokeColor(WebCore::Color(0, 0, 255), WebCore::ColorSpaceDeviceRGB);
graphicsContext.strokeRect(transformation.mapRect(wkViewport), 1.0);
graphicsContext.setStrokeColor(WebCore::Color(255, 0, 0), WebCore::ColorSpaceDeviceRGB);
graphicsContext.strokeRect(transformation.mapRect(uiViewport), 1.0);
graphicsContext.restore();
delete bufferPlatformGraphicsContext;
releaseBufferDrawable(windowBuffer);
#endif
#if DEBUG_CHECKERBOARD
static double lastCheckeredTime = 0;
if (blitCheckered && !lastCheckeredTime) {
lastCheckeredTime = WTF::currentTime();
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"Blitting checkered pattern at %f\n", lastCheckeredTime);
} else if (blitCheckered && lastCheckeredTime) {
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"Blitting checkered pattern at %f\n", WTF::currentTime());
} else if (!blitCheckered && lastCheckeredTime) {
double time = WTF::currentTime();
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"Blitting over checkered pattern at %f took %f\n", time, time - lastCheckeredTime);
lastCheckeredTime = 0;
}
#endif
invalidateWindow(dstRect);
if (blittingDirectlyToCompositingWindow && !blittedTiles.isEmpty()) {
pthread_mutex_lock(&m_blitGenerationLock);
++m_blitGeneration;
for (unsigned int i = 0; i < blittedTiles.size(); ++i)
blittedTiles[i]->setBlitGeneration(m_blitGeneration);
clock_gettime(CLOCK_REALTIME, &m_currentBlitEnd);
m_currentBlitEnd.tv_nsec += 30 * 1000 * 1000;
if (m_currentBlitEnd.tv_nsec >= 1000000000L) {
m_currentBlitEnd.tv_sec += 1;
m_currentBlitEnd.tv_nsec -= 1000000000L;
}
pthread_mutex_unlock(&m_blitGenerationLock);
pthread_cond_signal(&m_blitGenerationCond);
}
}
Platform::IntRect BackingStorePrivate::blitTileRect(TileBuffer* tileBuffer,
const TileRect& tileRect,
const Platform::IntPoint& origin,
const WebCore::TransformationMatrix& matrix,
BackingStoreGeometry* state)
{
if (!m_webPage->isVisible() || !isActive())
return Platform::IntRect();
Platform::IntRect dirtyTileRect = tileRect.second;
Platform::IntRect dirtyRect = mapFromTilesToTransformedContents(tileRect, state->backingStoreRect());
dirtyRect.move(-origin.x(), -origin.y());
dirtyRect = matrix.mapRect(dirtyRect);
if (!matrix.isIdentity()) {
dirtyRect.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
}
ASSERT(!dirtyRect.isEmpty());
ASSERT(!dirtyTileRect.isEmpty());
if (dirtyRect.isEmpty() || dirtyTileRect.isEmpty())
return Platform::IntRect();
blitToWindow(dirtyRect, tileBuffer->nativeBuffer(), dirtyTileRect,
false , 255);
return dirtyRect;
}
#if USE(ACCELERATED_COMPOSITING)
void BackingStorePrivate::blendCompositingSurface(const Platform::IntRect& dstRect)
{
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)(const Platform::IntRect&);
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
BlackBerry::Platform::createMethodCallMessage<FunctionType, BackingStorePrivate, Platform::IntRect>(
&BackingStorePrivate::blendCompositingSurface, this, dstRect));
return;
}
BackingStoreCompositingSurface* compositingSurface =
SurfacePool::globalSurfacePool()->compositingSurface();
if (!compositingSurface || !m_webPage->isVisible())
return;
WebCore::LayerRenderingResults lastCompositingResults = m_webPage->d->lastCompositingResults();
for (size_t i = 0; i < lastCompositingResults.holePunchRectSize(); i++) {
Platform::IntRect holePunchRect = lastCompositingResults.holePunchRect(i);
holePunchRect.intersect(dstRect);
holePunchRect.intersect(Platform::IntRect(
Platform::IntPoint(0, 0), surfaceSize()));
if (!holePunchRect.isEmpty())
clearWindow(holePunchRect, 0, 0, 0, 0);
}
CompositingSurfaceBuffer* frontBuffer = compositingSurface->frontBuffer();
IntRectList rects = lastCompositingResults.dirtyRegion.rects();
for (size_t i = 0; i < rects.size(); ++i) {
rects[i].intersect(dstRect);
#if DEBUG_COMPOSITING_DIRTY_REGION
clearBuffer(buffer(), rects[i], 255, 0, 0, 128);
#endif
blitToWindow(rects[i], frontBuffer->nativeBuffer(), rects[i], true , 255);
}
}
void BackingStorePrivate::clearCompositingSurface()
{
BackingStoreCompositingSurface* compositingSurface =
SurfacePool::globalSurfacePool()->compositingSurface();
if (!compositingSurface)
return;
CompositingSurfaceBuffer* frontBuffer = compositingSurface->frontBuffer();
BlackBerry::Platform::Graphics::clearBuffer(frontBuffer->nativeBuffer(), Platform::IntRect(Platform::IntPoint(), frontBuffer->surfaceSize()), 0, 0, 0, 0);
}
#endif // USE(ACCELERATED_COMPOSITING)
void BackingStorePrivate::blitHorizontalScrollbar(const Platform::IntPoint& scrollPosition)
{
if (!m_webPage->isVisible())
return;
ASSERT(m_client->scrollsHorizontally());
m_webPage->client()->drawHorizontalScrollbar();
}
void BackingStorePrivate::blitVerticalScrollbar(const Platform::IntPoint& scrollPosition)
{
if (!m_webPage->isVisible())
return;
ASSERT(m_client->scrollsVertically());
m_webPage->client()->drawVerticalScrollbar();
}
bool BackingStorePrivate::isTileVisible(const TileIndex& index) const
{
TileRect tileRect;
tileRect.first = index;
tileRect.second = this->tileRect();
return mapFromTilesToTransformedContents(tileRect).intersects(visibleContentsRect());
}
bool BackingStorePrivate::isTileVisible(const Platform::IntPoint& origin) const
{
return Platform::IntRect(origin, tileSize()).intersects(visibleContentsRect());
}
Platform::IntRect BackingStorePrivate::visibleTilesRect() const
{
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
Platform::IntRect rect;
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
TileRect tileRect;
tileRect.first = it->first;
tileRect.second = this->tileRect();
Platform::IntRect tile = mapFromTilesToTransformedContents(tileRect);
if (tile.intersects(visibleContentsRect()))
rect = Platform::unionOfRects(rect, tile);
}
return rect;
}
Platform::IntRect BackingStorePrivate::tileVisibleContentsRect(const TileIndex& index) const
{
if (!isTileVisible(index))
return Platform::IntRect();
return tileContentsRect(index, visibleContentsRect());
}
Platform::IntRect BackingStorePrivate::tileUnclippedVisibleContentsRect(const TileIndex& index) const
{
if (!isTileVisible(index))
return Platform::IntRect();
return tileContentsRect(index, unclippedVisibleContentsRect());
}
Platform::IntRect BackingStorePrivate::tileContentsRect(const TileIndex& index,
const Platform::IntRect& contents) const
{
return tileContentsRect(index, contents, frontState());
}
Platform::IntRect BackingStorePrivate::tileContentsRect(const TileIndex& index,
const Platform::IntRect& contents,
BackingStoreGeometry* state) const
{
TileRectList tileRectList = mapFromTransformedContentsToTiles(contents, state);
for (size_t i = 0; i < tileRectList.size(); ++i) {
TileRect tileRect = tileRectList[i];
if (index == tileRect.first)
return tileRect.second;
}
return Platform::IntRect();
}
void BackingStorePrivate::resetRenderQueue()
{
m_renderQueue->reset();
}
void BackingStorePrivate::clearVisibleZoom()
{
m_renderQueue->clearVisibleZoom();
}
void BackingStorePrivate::resetTiles(bool resetBackground)
{
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it)
resetTile(it->first, it->second, resetBackground);
}
void BackingStorePrivate::updateTiles(bool updateVisible, bool immediate)
{
if (!isActive())
return;
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
bool isVisible = isTileVisible(it->first);
if (!updateVisible && isVisible)
continue;
updateTile(it->first, immediate);
}
}
void BackingStorePrivate::updateTilesForScrollOrNotRenderedRegion(bool checkLoading)
{
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
Platform::IntRect backingStoreRect = currentState->backingStoreRect();
bool isLoading = m_client->loadState() == WebPagePrivate::Committed;
bool forceVisible = checkLoading && isLoading;
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
TileIndex index = it->first;
BackingStoreTile* tile = it->second;
bool isVisible = isTileVisible(index);
Platform::IntRect rect(originOfTile(index), tileSize());
if (tile->isCommitted()
&& m_renderQueue->regularRenderJobsPreviouslyAttemptedButNotRendered(rect)) {
if (isVisible) {
Platform::IntRectRegion tileNotRenderedRegion
= Platform::IntRectRegion::intersectRegions(
m_renderQueue->regularRenderJobsNotRenderedRegion(),
rect);
clearAndUpdateTileOfNotRenderedRegion(index,
tile,
tileNotRenderedRegion,
backingStoreRect,
false );
#if DEBUG_BACKINGSTORE
Platform::IntRect extents = tileNotRenderedRegion.extents();
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"BackingStorePrivate::updateTilesForScroll did clear tile %d,%d %dx%d",
extents.x(), extents.y(), extents.width(), extents.height());
#endif
}
updateTile(index, false );
} else if (isVisible
&& (forceVisible || !tile->frontBuffer()->isRendered(tileVisibleContentsRect(index)))
&& !isCurrentVisibleJob(index, tile, backingStoreRect))
updateTile(index, false );
}
}
void BackingStorePrivate::resetTile(const TileIndex& index, BackingStoreTile* tile, bool resetBackground)
{
if (!m_webPage->isVisible())
return;
if (!isActive()) {
m_webPage->d->setShouldResetTilesWhenShown(true);
return;
}
TileRect tileRect;
tileRect.first = index;
tileRect.second = this->tileRect();
m_renderQueue->clear(mapFromTilesToTransformedContents(tileRect), resetBackground );
if (resetBackground)
tile->reset();
}
void BackingStorePrivate::updateTile(const TileIndex& index, bool immediate)
{
if (!isActive())
return;
TileRect tileRect;
tileRect.first = index;
tileRect.second = this->tileRect();
Platform::IntRect updateRect = mapFromTilesToTransformedContents(tileRect);
RenderQueue::JobType jobType = isTileVisible(index) ? RenderQueue::VisibleScroll : RenderQueue::NonVisibleScroll;
if (immediate)
render(updateRect);
else
m_renderQueue->addToQueue(jobType, updateRect);
}
void BackingStorePrivate::updateTile(const Platform::IntPoint& origin, bool immediate)
{
if (!isActive())
return;
Platform::IntRect updateRect = Platform::IntRect(origin, tileSize());
RenderQueue::JobType jobType = isTileVisible(origin) ? RenderQueue::VisibleScroll : RenderQueue::NonVisibleScroll;
if (immediate)
render(updateRect);
else
m_renderQueue->addToQueue(jobType, updateRect);
}
Platform::IntRect BackingStorePrivate::mapFromTilesToTransformedContents(const BackingStorePrivate::TileRect& tileRect) const
{
return mapFromTilesToTransformedContents(tileRect, frontState()->backingStoreRect());
}
Platform::IntRect BackingStorePrivate::mapFromTilesToTransformedContents(const BackingStorePrivate::TileRect& tileRect, const Platform::IntRect& backingStoreRect) const
{
TileIndex index = tileRect.first;
Platform::IntRect rect = tileRect.second;
const Platform::IntPoint originOfTile = this->originOfTile(index, backingStoreRect);
rect.move(originOfTile.x(), originOfTile.y());
return rect;
}
BackingStorePrivate::TileRectList BackingStorePrivate::mapFromTransformedContentsToAbsoluteTileBoundaries(const Platform::IntRect& rect) const
{
if (!m_webPage->isVisible() || !isActive()) {
ASSERT_NOT_REACHED();
return TileRectList();
}
TileRectList tileRectList;
int firstXOffset = rect.x() / tileWidth();
int firstYOffset = rect.y() / tileHeight();
int lastXOffset = (rect.right() - 1) / tileWidth();
int lastYOffset = (rect.bottom() - 1) / tileHeight();
for (int i = firstXOffset; i <= lastXOffset; ++i) {
for (int j = firstYOffset; j <= lastYOffset; ++j) {
const int dstX = (i == firstXOffset) ? rect.x() : i * tileWidth();
const int dstY = (j == firstYOffset) ? rect.y() : j * tileHeight();
const int dstRight = (i == lastXOffset) ? rect.right() : (i + 1) * tileWidth();
const int dstBottom = (j == lastYOffset) ? rect.bottom() : (j + 1) * tileHeight();
const int srcX = dstX % tileWidth();
const int srcY = dstY % tileHeight();
TileRect tileRect;
tileRect.first = TileIndex(i, j);
tileRect.second = Platform::IntRect(srcX, srcY, dstRight - dstX, dstBottom - dstY);
tileRectList.append(tileRect);
}
}
return tileRectList;
}
BackingStorePrivate::TileRectList BackingStorePrivate::mapFromTransformedContentsToTiles(const Platform::IntRect& rect) const
{
return mapFromTransformedContentsToTiles(rect, frontState());
}
BackingStorePrivate::TileRectList BackingStorePrivate::mapFromTransformedContentsToTiles(const Platform::IntRect& rect, BackingStoreGeometry* state) const
{
TileMap tileMap = state->tileMap();
TileRectList tileRectList;
TileMap::const_iterator end = tileMap.end();
for (TileMap::const_iterator it = tileMap.begin(); it != end; ++it) {
TileIndex index = it->first;
BackingStoreTile* tile = it->second;
Platform::IntRect r = rect;
const Platform::IntPoint originOfTile = this->originOfTile(index, state->backingStoreRect());
r.move(-(originOfTile.x()), -(originOfTile.y()));
r.intersect(tile->rect());
if (r.isEmpty())
continue;
TileRect tileRect;
tileRect.first = index;
tileRect.second = r;
tileRectList.append(tileRect);
}
return tileRectList;
}
void BackingStorePrivate::updateTileMatrixIfNeeded()
{
scrollBackingStore(0, 0);
}
void BackingStorePrivate::contentsSizeChanged(const Platform::IntSize&)
{
updateTileMatrixIfNeeded();
}
void BackingStorePrivate::scrollChanged(const Platform::IntPoint&)
{
}
void BackingStorePrivate::transformChanged()
{
if (!m_webPage->isVisible())
return;
if (!isActive()) {
m_renderQueue->reset();
m_renderQueue->addToQueue(RenderQueue::VisibleZoom, visibleContentsRect());
m_webPage->d->setShouldResetTilesWhenShown(true);
return;
}
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
bool hasCurrentVisibleZoomJob = m_renderQueue->hasCurrentVisibleZoomJob();
bool isLoading = m_client->isLoading();
if (isLoading) {
if (!hasCurrentVisibleZoomJob)
m_visibleTileBufferRect = visibleContentsRect();
TileRectList tileRectList = mapFromTransformedContentsToTiles(visibleContentsRect());
for (size_t i = 0; i < tileRectList.size(); ++i) {
TileRect tileRect = tileRectList[i];
TileIndex index = tileRect.first;
Platform::IntRect dirtyTileRect = tileRect.second;
BackingStoreTile* tile = currentMap.get(index);
tileRect.second = this->tileRect();
Platform::IntRect wholeRect = mapFromTilesToTransformedContents(tileRect);
m_renderQueue->addToQueue(RenderQueue::VisibleZoom, wholeRect);
if (!hasCurrentVisibleZoomJob) {
Platform::IntPoint difference = this->originOfTile(index) - m_visibleTileBufferRect.location();
Platform::IntSize offset = Platform::IntSize(difference.x(), difference.y());
Platform::IntRect dirtyRect = dirtyTileRect;
dirtyRect.move(offset.width(), offset.height());
BackingStoreTile* visibleTileBuffer
= SurfacePool::globalSurfacePool()->visibleTileBuffer();
ASSERT(visibleTileBuffer->size() == Platform::IntSize(m_webPage->d->transformedViewportSize()));
BlackBerry::Platform::Graphics::blitToBuffer(
visibleTileBuffer->frontBuffer()->nativeBuffer(), dirtyRect,
tile->frontBuffer()->nativeBuffer(), dirtyTileRect);
}
}
}
m_renderQueue->reset();
resetTiles(true );
}
void BackingStorePrivate::orientationChanged()
{
updateTileMatrixIfNeeded();
createVisibleTileBuffer();
}
void BackingStorePrivate::actualVisibleSizeChanged(const Platform::IntSize& size)
{
}
static void createVisibleTileBufferForWebPage(WebPagePrivate* page)
{
ASSERT(page);
SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
surfacePool->initializeVisibleTileBuffer(page->transformedViewportSize());
}
void BackingStorePrivate::createSurfaces()
{
BackingStoreGeometry* currentState = frontState();
TileMap currentMap = currentState->tileMap();
ASSERT(currentMap.isEmpty());
if (m_webPage->isVisible()) {
ASSERT_NOT_REACHED();
return;
}
SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
surfacePool->initialize(tileSize());
if (surfacePool->isEmpty()) return;
const Divisor divisor = bestDivisor(expandedContentsSize(), tileWidth(), tileHeight(), minimumNumberOfTilesWide(), minimumNumberOfTilesHigh(), m_preferredTileMatrixDimension);
int numberOfTilesWide = divisor.first;
int numberOfTilesHigh = divisor.second;
const SurfacePool::TileList tileList = surfacePool->tileList();
ASSERT(static_cast<int>(tileList.size()) >= (numberOfTilesWide * numberOfTilesHigh));
TileMap newTileMap;
for (int y = 0; y < numberOfTilesHigh; ++y) {
for (int x = 0; x < numberOfTilesWide; ++x) {
TileIndex index(x, y);
newTileMap.add(index, tileList.at(x + y * numberOfTilesWide));
}
}
backState()->setNumberOfTilesWide(divisor.first);
backState()->setNumberOfTilesHigh(divisor.second);
backState()->setTileMap(newTileMap);
swapState();
createVisibleTileBufferForWebPage(m_webPage->d);
}
void BackingStorePrivate::createVisibleTileBuffer()
{
if (!m_webPage->isVisible() || !isActive())
return;
createVisibleTileBufferForWebPage(m_webPage->d);
}
Platform::IntPoint BackingStorePrivate::originOfTile(const TileIndex& index) const
{
return originOfTile(index, frontState()->backingStoreRect());
}
Platform::IntPoint BackingStorePrivate::originOfTile(const TileIndex& index, const Platform::IntRect& backingStoreRect) const
{
return Platform::IntPoint(backingStoreRect.x() + (index.i() * tileWidth()),
backingStoreRect.y() + (index.j() * tileHeight()));
}
int BackingStorePrivate::minimumNumberOfTilesWide() const
{
return static_cast<int>(ceilf(m_client->transformedViewportSize().width() / static_cast<float>(tileWidth()))) + 1;
}
int BackingStorePrivate::minimumNumberOfTilesHigh() const
{
return static_cast<int>(ceilf(m_client->transformedViewportSize().height() / static_cast<float>(tileHeight()))) + 1;
}
Platform::IntSize BackingStorePrivate::expandedContentsSize() const
{
return m_client->transformedContentsSize().expandedTo(m_client->transformedViewportSize());
}
int BackingStorePrivate::tileWidth()
{
static int tileWidth = BlackBerry::Platform::Graphics::Screen::primaryScreen()->landscapeWidth();
return tileWidth;
}
int BackingStorePrivate::tileHeight()
{
static int tileHeight = BlackBerry::Platform::Graphics::Screen::primaryScreen()->landscapeHeight();
return tileHeight;
}
Platform::IntSize BackingStorePrivate::tileSize()
{
return Platform::IntSize(tileWidth(), tileHeight());
}
Platform::IntRect BackingStorePrivate::tileRect()
{
return Platform::IntRect(0, 0, tileWidth(), tileHeight());
}
void BackingStorePrivate::renderContents(BlackBerry::Platform::Graphics::Drawable* drawable,
double scale,
const Platform::IntRect& contentsRect) const
{
if (!drawable || contentsRect.isEmpty())
return;
PlatformGraphicsContext* platformGraphicsContext = SurfacePool::globalSurfacePool()->createPlatformGraphicsContext(drawable);
GraphicsContext graphicsContext(platformGraphicsContext);
graphicsContext.translate(-contentsRect.x(), -contentsRect.y());
WebCore::IntRect transformedContentsRect(contentsRect.x(), contentsRect.y(), contentsRect.width(), contentsRect.height());
if (scale != 1.0) {
TransformationMatrix matrix;
matrix.scale(1.0 / scale);
transformedContentsRect = matrix.mapRect(transformedContentsRect);
const int atLeastOneDevicePixel = static_cast<int>(ceilf(1.0 / scale));
transformedContentsRect.inflate(atLeastOneDevicePixel);
graphicsContext.scale(FloatSize(scale, scale));
}
graphicsContext.clip(transformedContentsRect);
m_client->frame()->view()->paintContents(&graphicsContext, transformedContentsRect);
delete platformGraphicsContext;
}
void BackingStorePrivate::renderContents(BlackBerry::Platform::Graphics::Buffer* tileBuffer,
const Platform::IntPoint& surfaceOffset,
const Platform::IntRect& contentsRect) const
{
if (!m_webPage->isVisible() && tileBuffer)
return;
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"BackingStorePrivate::renderContents tileBuffer=0x%x surfaceOffset=(%d,%d) contentsRect=(%d,%d %dx%d)",
tileBuffer, surfaceOffset.x(), surfaceOffset.y(),
contentsRect.x(), contentsRect.y(), contentsRect.width(), contentsRect.height());
#endif
ASSERT(!m_webPage->d->mainFrame()->view()->needsLayout());
Platform::IntSize contentsSize = m_client->contentsSize();
Color backgroundColor(m_webPage->settings()->backgroundColor());
BlackBerry::Platform::Graphics::Buffer* targetBuffer = tileBuffer
? tileBuffer
: buffer();
if (contentsSize.isEmpty()
|| !Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedContentsSize()).contains(contentsRect)
|| backgroundColor.hasAlpha()) {
BlackBerry::Platform::IntRect clearRect = BlackBerry::Platform::IntRect(
contentsRect.x() - surfaceOffset.x(), contentsRect.y() - surfaceOffset.y(),
contentsRect.width(), contentsRect.height());
BlackBerry::Platform::Graphics::clearBuffer(targetBuffer, clearRect,
backgroundColor.red(), backgroundColor.green(),
backgroundColor.blue(), backgroundColor.alpha());
}
if (contentsSize.isEmpty())
return;
#if USE(ACCELERATED_COMPOSITING)
if (m_webPage->d->commitRootLayerIfNeeded())
m_needsDrawLayersOnCommit = true;
#endif
BlackBerry::Platform::Graphics::Drawable* bufferDrawable =
BlackBerry::Platform::Graphics::lockBufferDrawable(targetBuffer);
PlatformGraphicsContext* bufferPlatformGraphicsContext = bufferDrawable
? SurfacePool::globalSurfacePool()->createPlatformGraphicsContext(bufferDrawable)
: 0;
PlatformGraphicsContext* targetPlatformGraphicsContext = bufferPlatformGraphicsContext
? bufferPlatformGraphicsContext
: SurfacePool::globalSurfacePool()->lockTileRenderingSurface();
ASSERT(targetPlatformGraphicsContext);
{
GraphicsContext graphicsContext(targetPlatformGraphicsContext);
graphicsContext.save();
graphicsContext.translate(-surfaceOffset.x(), -surfaceOffset.y());
AffineTransform affineTransform(
m_webPage->d->transformationMatrix()->a(),
m_webPage->d->transformationMatrix()->b(),
m_webPage->d->transformationMatrix()->c(),
m_webPage->d->transformationMatrix()->d(),
m_webPage->d->transformationMatrix()->e(),
m_webPage->d->transformationMatrix()->f());
graphicsContext.concatCTM(affineTransform);
Platform::IntRect untransformedContentsRect = m_webPage->d->mapFromTransformed(contentsRect);
const int atLeastOneDevicePixel =
static_cast<int>(ceilf(1.0 / m_webPage->d->transformationMatrix()->a()));
untransformedContentsRect.inflate(atLeastOneDevicePixel, atLeastOneDevicePixel);
untransformedContentsRect.intersect(Platform::IntRect(Platform::IntPoint(0, 0), contentsSize));
graphicsContext.clip(untransformedContentsRect);
if (int leftOverFlow = m_client->frame()->view()->minimumScrollPosition().x()) {
untransformedContentsRect.move(leftOverFlow, 0);
graphicsContext.translate(-leftOverFlow, 0);
}
m_client->frame()->view()->paintContents(&graphicsContext, untransformedContentsRect);
#if ENABLE(INSPECTOR)
if (m_webPage->d->m_page->inspectorController()->enabled()) {
WebCore::IntPoint scrollPosition = m_client->frame()->view()->scrollPosition();
graphicsContext.translate(scrollPosition.x(), scrollPosition.y());
m_webPage->d->m_page->inspectorController()->drawHighlight(graphicsContext);
}
#endif
graphicsContext.restore();
}
delete bufferPlatformGraphicsContext;
if (bufferDrawable)
releaseBufferDrawable(targetBuffer);
else {
const Platform::IntPoint dstPoint(contentsRect.x() - surfaceOffset.x(),
contentsRect.y() - surfaceOffset.y());
const Platform::IntRect dstRect(dstPoint, contentsRect.size());
const Platform::IntRect srcRect = dstRect;
SurfacePool::globalSurfacePool()->releaseTileRenderingSurface(targetPlatformGraphicsContext);
BlackBerry::Platform::Graphics::blitToBuffer(targetBuffer, dstRect, BlackBerry::Platform::Graphics::drawingSurface(), srcRect);
}
}
#if DEBUG_FAT_FINGERS
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)
{
Platform::IntRect drawRect(srcRect);
drawRect.intersect(dstRect);
if (!drawRect.isEmpty())
BlackBerry::Platform::Graphics::clearBuffer(dstBuffer, drawRect, red, green, blue, 128);
}
#endif
void BackingStorePrivate::blitToWindow(const Platform::IntRect& dstRect,
const BlackBerry::Platform::Graphics::Buffer* srcBuffer,
const Platform::IntRect& srcRect,
bool blend,
unsigned char globalAlpha)
{
ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
windowFrontBufferState()->clearBlittedRegion(dstRect);
windowBackBufferState()->addBlittedRegion(dstRect);
BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
ASSERT(dstBuffer);
ASSERT(srcBuffer);
if (!dstBuffer)
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't blitToWindow");
BlackBerry::Platform::Graphics::BlendMode blendMode = blend
? BlackBerry::Platform::Graphics::SourceOver
: BlackBerry::Platform::Graphics::SourceCopy;
BlackBerry::Platform::Graphics::blitToBuffer(dstBuffer, dstRect, srcBuffer, srcRect, blendMode, globalAlpha);
#if DEBUG_FAT_FINGERS
drawDebugRect(dstBuffer, dstRect, FatFingers::m_debugFatFingerRect, 210, 210, 250);
drawDebugRect(dstBuffer, dstRect, Platform::IntRect(FatFingers::m_debugFatFingerClickPosition, Platform::IntSize(3, 3)), 0, 0, 0);
drawDebugRect(dstBuffer, dstRect, Platform::IntRect(FatFingers::m_debugFatFingerAdjustedPosition, Platform::IntSize(5, 5)), 100, 100, 100);
#endif
}
void BackingStorePrivate::checkerWindow(const Platform::IntRect& dstRect,
const Platform::IntPoint& contentsOrigin,
double contentsScale)
{
ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
windowFrontBufferState()->clearBlittedRegion(dstRect);
windowBackBufferState()->addBlittedRegion(dstRect);
BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
ASSERT(dstBuffer);
if (!dstBuffer)
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't checkerWindow");
Color color(m_webPage->settings()->backgroundColor());
unsigned char alpha = color.alpha();
BlackBerry::Platform::Graphics::checkerBuffer(dstBuffer, dstRect, contentsOrigin, contentsScale, alpha);
}
void BackingStorePrivate::invalidateWindow()
{
if (BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread())
invalidateWindow(m_webPage->client()->userInterfaceBlittedDestinationRect());
else
invalidateWindow(Platform::IntRect(Platform::IntPoint(0, 0), m_client->transformedViewportSize()));
}
void BackingStorePrivate::invalidateWindow(const Platform::IntRect& dst)
{
if (dst.isEmpty())
return;
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread() && !shouldDirectRenderingToWindow()) {
typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)(const Platform::IntRect&);
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
BlackBerry::Platform::createMethodCallMessage<FunctionType, BackingStorePrivate, Platform::IntRect>(
&BackingStorePrivate::invalidateWindow, this, dst));
return;
}
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::invalidateWindow dst = %s", dst.toString().c_str());
#endif
copyPreviousContentsToBackSurfaceOfWindow();
Platform::IntRect dstRect = dst;
Platform::IntRect viewportRect(Platform::IntPoint(0, 0), m_client->transformedViewportSize());
dstRect.intersect(viewportRect);
if (dstRect.width() <= 0 || dstRect.height() <= 0)
return;
#if DEBUG_BACKINGSTORE
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical, "BackingStorePrivate::invalidateWindow posting = %s", dstRect.toString().c_str());
#endif
m_currentWindowBackBuffer = (m_currentWindowBackBuffer + 1) % 2;
if (Window* window = m_webPage->client()->window())
window->post(dstRect);
}
void BackingStorePrivate::clearWindow()
{
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread() && !shouldDirectRenderingToWindow()) {
typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)();
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
BlackBerry::Platform::createMethodCallMessage<FunctionType, BackingStorePrivate>(
&BackingStorePrivate::clearWindow, this));
return;
}
BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
ASSERT(dstBuffer);
if (!dstBuffer)
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't clearWindow");
windowFrontBufferState()->clearBlittedRegion();
windowBackBufferState()->addBlittedRegion(Platform::IntRect(
Platform::IntPoint(0, 0), surfaceSize()));
Color color(m_webPage->settings()->backgroundColor());
BlackBerry::Platform::Graphics::clearBuffer(dstBuffer,
color.red(), color.green(), color.blue(), color.alpha());
}
void BackingStorePrivate::clearWindow(const Platform::IntRect& rect,
unsigned char red,
unsigned char green,
unsigned char blue,
unsigned char alpha)
{
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread() && !shouldDirectRenderingToWindow()) {
typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)(const Platform::IntRect&,
unsigned char,
unsigned char,
unsigned char,
unsigned char);
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
BlackBerry::Platform::createMethodCallMessage<FunctionType,
BackingStorePrivate,
Platform::IntRect,
unsigned char,
unsigned char,
unsigned char,
unsigned char>(
&BackingStorePrivate::clearWindow, this, rect, red, green, blue, alpha));
return;
}
BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
ASSERT(dstBuffer);
if (!dstBuffer)
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelWarn, "Empty window buffer, couldn't clearWindow");
windowFrontBufferState()->clearBlittedRegion(rect);
windowBackBufferState()->addBlittedRegion(rect);
BlackBerry::Platform::Graphics::clearBuffer(dstBuffer, rect, red, green, blue, alpha);
}
bool BackingStorePrivate::isScrollingOrZooming() const
{
BackingStoreMutexLocker locker(const_cast<BackingStorePrivate*>(this));
return m_isScrollingOrZooming;
}
void BackingStorePrivate::setScrollingOrZooming(bool scrollingOrZooming, bool shouldBlit)
{
{
BackingStoreMutexLocker locker(this);
m_isScrollingOrZooming = scrollingOrZooming;
}
#if !ENABLE_REPAINTONSCROLL
m_suspendRenderJobs = scrollingOrZooming; #endif
if (!m_webPage->settings()->shouldRenderAnimationsOnScrollOrZoom())
m_suspendRegularRenderJobs = scrollingOrZooming;
if (scrollingOrZooming)
m_renderQueue->setCurrentRegularRenderJobBatchUnderPressure(false);
#if ENABLE_SCROLLBARS
else if (shouldBlit && !shouldDirectRenderingToWindow())
blitVisibleContents();
#endif
}
void BackingStorePrivate::lockBackingStore()
{
pthread_mutex_lock(&m_mutex);
}
void BackingStorePrivate::unlockBackingStore()
{
pthread_mutex_unlock(&m_mutex);
}
BackingStoreGeometry* BackingStorePrivate::frontState() const
{
return reinterpret_cast<BackingStoreGeometry*>(m_frontState);
}
BackingStoreGeometry* BackingStorePrivate::backState() const
{
return reinterpret_cast<BackingStoreGeometry*>(m_backState);
}
void BackingStorePrivate::swapState()
{
unsigned front = reinterpret_cast<unsigned>(frontState());
unsigned back = reinterpret_cast<unsigned>(backState());
_smp_xchg(&m_frontState, back);
_smp_xchg(&m_backState, front);
BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
}
BackingStoreWindowBufferState* BackingStorePrivate::windowFrontBufferState() const
{
return &m_windowBufferState[(m_currentWindowBackBuffer + 1) % 2];
}
BackingStoreWindowBufferState* BackingStorePrivate::windowBackBufferState() const
{
return &m_windowBufferState[m_currentWindowBackBuffer];
}
#if USE(ACCELERATED_COMPOSITING)
bool BackingStorePrivate::drawLayersOnCommitIfNeeded()
{
if (!m_needsDrawLayersOnCommit)
return false;
m_needsDrawLayersOnCommit = false;
m_webPage->d->drawLayersOnCommit();
return true;
}
void BackingStorePrivate::drawAndBlendLayersForDirectRendering(const Platform::IntRect& dirtyRect)
{
ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread())
return;
WebCore::IntRect contentsRect = visibleContentsRect();
WebCore::FloatRect untransformedContentsRect = m_webPage->d->mapFromTransformedFloatRect(WebCore::FloatRect(contentsRect));
WebCore::IntRect contentsScreenRect = m_client->mapFromTransformedContentsToTransformedViewport(contentsRect);
WebCore::IntRect dstRect = intersection(contentsScreenRect,
WebCore::IntRect(WebCore::IntPoint(0, 0), m_webPage->d->transformedViewportSize()));
m_needsDrawLayersOnCommit = false;
if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
compositor->drawLayers(dstRect, untransformedContentsRect);
#if ENABLE_COMPOSITING_SURFACE
Platform::IntRect visibleDirtyRect = dirtyRect;
visibleDirtyRect.intersect(visibleContentsRect());
visibleDirtyRect = m_client->mapFromTransformedContentsToTransformedViewport(visibleDirtyRect);
blendCompositingSurface(visibleDirtyRect);
#endif
}
#endif
bool BackingStorePrivate::isActive() const
{
return BackingStorePrivate::s_currentBackingStoreOwner == m_webPage && SurfacePool::globalSurfacePool()->isActive();
}
BackingStore::BackingStore(WebPage* webPage, BackingStoreClient* client)
: d(new BackingStorePrivate)
{
d->m_webPage = webPage;
d->m_client = client;
}
BackingStore::~BackingStore()
{
deleteGuardedObject(d);
d = 0;
}
void BackingStore::createSurface()
{
static bool initialized = false;
if (!initialized) {
BlackBerry::Platform::Graphics::initialize();
initialized = true;
}
d->createSurfaces();
d->m_webPage->setFocused(true);
}
void BackingStore::suspendScreenAndBackingStoreUpdates()
{
d->suspendScreenAndBackingStoreUpdates();
}
void BackingStore::resumeScreenAndBackingStoreUpdates(ResumeUpdateOperation op)
{
d->resumeScreenAndBackingStoreUpdates(op);
}
bool BackingStore::isScrollingOrZooming() const
{
return d->isScrollingOrZooming();
}
void BackingStore::setScrollingOrZooming(bool scrollingOrZooming)
{
d->setScrollingOrZooming(scrollingOrZooming);
}
void BackingStore::blitContents(const BlackBerry::Platform::IntRect& dstRect, const BlackBerry::Platform::IntRect& contents)
{
if (isDirectRenderingToWindow()) {
BlackBerry::Platform::log(BlackBerry::Platform::LogLevelCritical,
"BackingStore::blitContents operation not supported in direct rendering mode");
return;
}
d->blitContents(dstRect, contents);
}
void BackingStore::repaint(int x, int y, int width, int height,
bool contentChanged, bool immediate)
{
d->repaint(Platform::IntRect(x, y, width, height), contentChanged, immediate);
}
bool BackingStore::hasRenderJobs() const
{
return d->shouldPerformRenderJobs();
}
void BackingStore::renderOnIdle()
{
d->renderOnIdle();
}
bool BackingStore::isDirectRenderingToWindow() const
{
BackingStoreMutexLocker locker(d);
return d->shouldDirectRenderingToWindow();
}
void BackingStore::createBackingStoreMemory()
{
SurfacePool::globalSurfacePool()->createBuffers();
}
void BackingStore::releaseBackingStoreMemory()
{
SurfacePool::globalSurfacePool()->releaseBuffers();
}
bool BackingStore::defersBlit() const
{
return d->m_defersBlit;
}
void BackingStore::setDefersBlit(bool b)
{
d->m_defersBlit = b;
}
bool BackingStore::hasBlitJobs() const
{
#if USE(ACCELERATED_COMPOSITING)
WebPageCompositorPrivate* compositor = d->m_webPage->d->compositor();
if (compositor && compositor->client())
return false;
#endif
return d->m_hasBlitJobs;
}
void BackingStore::blitOnIdle()
{
#if USE(ACCELERATED_COMPOSITING)
WebPageCompositorPrivate* compositor = d->m_webPage->d->compositor();
if (compositor && compositor->client())
return;
#endif
d->blitVisibleContents(true );
}
Platform::IntSize BackingStorePrivate::surfaceSize() const
{
if (Window* window = m_webPage->client()->window())
return window->surfaceSize();
#if USE(ACCELERATED_COMPOSITING)
if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
return compositor->context()->surfaceSize();
#endif
return Platform::IntSize();
}
Platform::Graphics::Buffer* BackingStorePrivate::buffer() const
{
if (Window* window = m_webPage->client()->window())
return window->buffer();
#if USE(ACCELERATED_COMPOSITING)
if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
return compositor->context()->buffer();
#endif
return 0;
}
void BackingStore::drawContents(BlackBerry::Platform::Graphics::Drawable* drawable, double scale, const Platform::IntRect& contentsRect)
{
d->renderContents(drawable, scale, contentsRect);
}
}
}