#include "config.h"
#include "BackingStore.h"
#include "BackingStoreClient.h"
#include "BackingStoreTile.h"
#include "BackingStoreVisualizationViewportAccessor.h"
#include "BackingStore_p.h"
#include "FatFingers.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "InspectorController.h"
#include "InspectorInstrumentation.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 <BlackBerryPlatformExecutableMessage.h>
#include <BlackBerryPlatformGraphics.h>
#include <BlackBerryPlatformGraphicsContext.h>
#include <BlackBerryPlatformIntRectRegion.h>
#include <BlackBerryPlatformLog.h>
#include <BlackBerryPlatformMessage.h>
#include <BlackBerryPlatformMessageClient.h>
#include <BlackBerryPlatformPerformanceMonitor.h>
#include <BlackBerryPlatformScreen.h>
#include <BlackBerryPlatformSettings.h>
#include <BlackBerryPlatformViewportAccessor.h>
#include <BlackBerryPlatformWindow.h>
#include <graphics/AffineTransform.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_WEBCORE_REQUESTS 0
#define DEBUG_VISUALIZE 0
#define DEBUG_TILEMATRIX 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 {
WebPage* BackingStorePrivate::s_currentBackingStoreOwner = 0;
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;
}
Platform::IntRect BackingStoreGeometry::backingStoreRect() const
{
return Platform::IntRect(backingStoreOffset(), backingStoreSize());
}
Platform::IntSize BackingStoreGeometry::backingStoreSize() const
{
return Platform::IntSize(numberOfTilesWide() * BackingStorePrivate::tileWidth(), numberOfTilesHigh() * BackingStorePrivate::tileHeight());
}
bool BackingStoreGeometry::isTileCorrespondingToBuffer(TileIndex index, TileBuffer* tileBuffer) const
{
return tileBuffer
&& scale() == tileBuffer->lastRenderScale()
&& originOfTile(index) == tileBuffer->lastRenderOrigin();
}
BackingStorePrivate::BackingStorePrivate()
: m_suspendScreenUpdateCounterWebKitThread(0)
, m_suspendBackingStoreUpdates(0)
, m_suspendGeometryUpdates(0)
, m_resumeOperation(BackingStore::None)
, m_suspendScreenUpdatesWebKitThread(true)
, m_suspendScreenUpdatesUserInterfaceThread(true)
, m_suspendRenderJobs(false)
, m_suspendRegularRenderJobs(false)
, m_tileMatrixContainsUsefulContent(false)
, m_tileMatrixNeedsUpdate(false)
, m_isScrollingOrZooming(false)
, m_webPage(0)
, m_client(0)
, m_renderQueue(adoptPtr(new RenderQueue(this)))
, m_hasBlitJobs(false)
, m_webPageBackgroundColor(WebCore::Color::white)
{
m_frontState = reinterpret_cast<unsigned>(new BackingStoreGeometry);
}
BackingStorePrivate::~BackingStorePrivate()
{
BackingStoreGeometry* front = reinterpret_cast<BackingStoreGeometry*>(m_frontState);
delete front;
m_frontState = 0;
}
void BackingStorePrivate::instrumentBeginFrame()
{
#if ENABLE(INSPECTOR)
WebPagePrivate::core(m_webPage)->inspectorController()->didBeginFrame();
#endif
}
void BackingStorePrivate::instrumentCancelFrame()
{
#if ENABLE(INSPECTOR)
WebPagePrivate::core(m_webPage)->inspectorController()->didCancelFrame();
#endif
}
bool BackingStorePrivate::isOpenGLCompositing() const
{
if (Window* window = m_webPage->client()->window())
return window->windowUsage() == Window::GLES2Usage;
return true;
}
void BackingStorePrivate::suspendBackingStoreUpdates()
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
if (m_suspendBackingStoreUpdates) {
BBLOG(Platform::LogLevelInfo,
"Backingstore already suspended, increasing suspend counter.");
}
++m_suspendBackingStoreUpdates;
}
void BackingStorePrivate::suspendGeometryUpdates()
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
if (m_suspendGeometryUpdates) {
BBLOG(Platform::LogLevelInfo,
"Backingstore geometry already suspended, increasing suspend counter.");
}
++m_suspendGeometryUpdates;
}
void BackingStorePrivate::suspendScreenUpdates()
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
if (m_suspendScreenUpdateCounterWebKitThread) {
BBLOG(Platform::LogLevelInfo,
"Screen already suspended, increasing suspend counter.");
}
++m_suspendScreenUpdateCounterWebKitThread;
updateSuspendScreenUpdateState();
}
void BackingStorePrivate::resumeBackingStoreUpdates()
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
ASSERT(m_suspendBackingStoreUpdates >= 1);
if (m_suspendBackingStoreUpdates < 1) {
Platform::logAlways(Platform::LogLevelCritical,
"Call mismatch: Backingstore hasn't been suspended, therefore won't resume!");
return;
}
if (m_suspendBackingStoreUpdates == 1)
setTileMatrixNeedsUpdate();
--m_suspendBackingStoreUpdates;
dispatchRenderJob();
}
void BackingStorePrivate::resumeGeometryUpdates()
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
ASSERT(m_suspendGeometryUpdates >= 1);
if (m_suspendGeometryUpdates < 1) {
Platform::logAlways(Platform::LogLevelCritical,
"Call mismatch: Backingstore geometry hasn't been suspended, therefore won't resume!");
return;
}
if (m_suspendGeometryUpdates == 1)
setTileMatrixNeedsUpdate();
--m_suspendGeometryUpdates;
dispatchRenderJob();
}
void BackingStorePrivate::resumeScreenUpdates(BackingStore::ResumeUpdateOperation op)
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
ASSERT(m_suspendScreenUpdateCounterWebKitThread);
if (!m_suspendScreenUpdateCounterWebKitThread) {
Platform::logAlways(Platform::LogLevelCritical,
"Call mismatch: Screen hasn't been suspended, therefore won't resume!");
return;
}
if (op == BackingStore::RenderAndBlit
|| (m_resumeOperation == BackingStore::None && op == BackingStore::Blit))
m_resumeOperation = op;
if (m_suspendScreenUpdateCounterWebKitThread >= 2) { BBLOG(Platform::LogLevelInfo,
"Screen and backingstore still suspended, decreasing suspend counter.");
--m_suspendScreenUpdateCounterWebKitThread;
return;
}
op = m_resumeOperation;
m_resumeOperation = BackingStore::None;
#if USE(ACCELERATED_COMPOSITING)
if (op != BackingStore::None) {
if (isOpenGLCompositing() && !isActive()) {
m_webPage->d->setCompositorDrawsRootLayer(true);
m_webPage->d->setNeedsOneShotDrawingSynchronization();
--m_suspendScreenUpdateCounterWebKitThread;
updateSuspendScreenUpdateState();
return;
}
m_webPage->d->setNeedsOneShotDrawingSynchronization();
}
#endif
if (op == BackingStore::RenderAndBlit) {
updateTileMatrixIfNeeded();
TileIndexList visibleTiles = visibleTileIndexes(frontState());
TileIndexList renderedTiles = render(visibleTiles);
if (renderedTiles.size() != visibleTiles.size()) {
for (unsigned i = 0; i < visibleTiles.size(); ++i) {
if (!renderedTiles.contains(visibleTiles[i])) {
Platform::IntRect tileRect(frontState()->originOfTile(visibleTiles[i]), tileSize());
m_renderQueue->addToQueue(RenderQueue::VisibleZoom, tileRect);
}
}
}
}
--m_suspendScreenUpdateCounterWebKitThread;
updateSuspendScreenUpdateState();
if (op == BackingStore::None)
return;
#if USE(ACCELERATED_COMPOSITING)
if (m_webPage->d->needsOneShotDrawingSynchronization())
m_webPage->d->updateLayoutAndStyleIfNeededRecursive();
m_webPage->d->commitRootLayerIfNeeded();
#else
if (op == BackingStore::Blit || op == BackingStore::RenderAndBlit)
blitVisibleContents();
#endif
}
void BackingStorePrivate::updateSuspendScreenUpdateState(bool* hasSyncedToUserInterfaceThread)
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
bool isBackingStoreUsable = isActive() && m_tileMatrixContainsUsefulContent
&& (m_suspendBackingStoreUpdates || !m_renderQueue->hasCurrentVisibleZoomJob());
bool shouldSuspend = m_suspendScreenUpdateCounterWebKitThread
|| !buffer()
|| !m_webPage->isVisible()
|| (!isBackingStoreUsable && !m_webPage->d->compositorDrawsRootLayer());
if (m_suspendScreenUpdatesWebKitThread == shouldSuspend) {
if (hasSyncedToUserInterfaceThread)
*hasSyncedToUserInterfaceThread = false;
return;
}
m_suspendScreenUpdatesWebKitThread = shouldSuspend;
m_suspendScreenUpdatesUserInterfaceThread = shouldSuspend;
BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
if (hasSyncedToUserInterfaceThread)
*hasSyncedToUserInterfaceThread = true;
}
void BackingStorePrivate::repaint(const Platform::IntRect& windowRect, bool contentChanged, bool immediate)
{
if (contentChanged && !windowRect.isEmpty()) {
const Platform::ViewportAccessor* viewportAccessor = m_webPage->webkitThreadViewportAccessor();
Platform::IntRect rect = viewportAccessor->roundToPixelFromDocumentContents(viewportAccessor->documentContentsFromViewport(windowRect));
rect.intersect(viewportAccessor->pixelContentsRect());
if (rect.isEmpty())
return;
#if DEBUG_WEBCORE_REQUESTS
Platform::logAlways(Platform::LogLevelCritical,
"BackingStorePrivate::repaint rect=%s contentChanged=%s immediate=%s",
rect.toString().c_str(),
contentChanged ? "true" : "false",
immediate ? "true" : "false");
#endif
if (immediate)
renderAndBlitImmediately(rect);
else
m_renderQueue->addToQueue(RenderQueue::RegularRender, rect);
}
}
void BackingStorePrivate::slowScroll(const Platform::IntSize& delta, const Platform::IntRect& windowRect, bool immediate)
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
#if DEBUG_BACKINGSTORE
double time = WTF::currentTime();
#endif
scrollingStartedHelper(delta);
const Platform::ViewportAccessor* viewportAccessor = m_webPage->webkitThreadViewportAccessor();
const Platform::IntRect rect = viewportAccessor->roundToPixelFromDocumentContents(viewportAccessor->documentContentsFromViewport(windowRect));
if (immediate)
renderAndBlitImmediately(rect);
else {
m_renderQueue->addToQueue(RenderQueue::VisibleScroll, rect);
if (!m_client->isClientGeneratedScroll())
blitVisibleContents();
}
#if DEBUG_BACKINGSTORE
double elapsed = WTF::currentTime() - time;
Platform::logAlways(Platform::LogLevelCritical, "BackingStorePrivate::slowScroll elapsed=%f", elapsed);
#endif
}
void BackingStorePrivate::scroll(const Platform::IntSize& delta, const Platform::IntRect&, const Platform::IntRect&)
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
#if DEBUG_BACKINGSTORE
double time = WTF::currentTime();
#endif
scrollingStartedHelper(delta);
if (!m_client->isClientGeneratedScroll())
blitVisibleContents();
#if DEBUG_BACKINGSTORE
double elapsed = WTF::currentTime() - time;
Platform::logAlways(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 isActive() && !m_suspendRenderJobs && !m_suspendBackingStoreUpdates && !m_renderQueue->isEmpty(!m_suspendRegularRenderJobs);
}
bool BackingStorePrivate::shouldPerformRegularRenderJobs() const
{
return shouldPerformRenderJobs() && !m_suspendRegularRenderJobs;
}
static const BlackBerry::Platform::Message::Type RenderJobMessageType = BlackBerry::Platform::Message::generateUniqueMessageType();
class RenderJobMessage : public BlackBerry::Platform::ExecutableMessage {
public:
RenderJobMessage(BlackBerry::Platform::MessageDelegate* delegate)
: BlackBerry::Platform::ExecutableMessage(delegate, BlackBerry::Platform::ExecutableMessage::UniqueCoalescing, RenderJobMessageType)
{ }
};
void BackingStorePrivate::dispatchRenderJob()
{
BlackBerry::Platform::MessageDelegate* messageDelegate = BlackBerry::Platform::createMethodDelegate(&BackingStorePrivate::renderJob, this);
BlackBerry::Platform::webKitThreadMessageClient()->dispatchMessage(new RenderJobMessage(messageDelegate));
}
void BackingStorePrivate::renderJob()
{
if (!shouldPerformRenderJobs())
return;
instrumentBeginFrame();
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelCritical, "BackingStorePrivate::renderJob");
#endif
m_renderQueue->render(!m_suspendRegularRenderJobs);
if (shouldPerformRenderJobs())
dispatchRenderJob();
}
Platform::IntSize BackingStorePrivate::expandedContentsSize() const
{
const Platform::ViewportAccessor* viewportAccessor = m_webPage->webkitThreadViewportAccessor();
return m_client->transformedViewportSize().expandedTo(viewportAccessor->pixelContentsSize());
}
Platform::IntRect BackingStorePrivate::expandedContentsRect() const
{
return Platform::IntRect(Platform::IntPoint(0, 0), expandedContentsSize());
}
Platform::IntRect BackingStorePrivate::visibleContentsRect() const
{
const Platform::ViewportAccessor* viewportAccessor = m_webPage->webkitThreadViewportAccessor();
Platform::IntRect rect = viewportAccessor->pixelViewportRect();
rect.intersect(viewportAccessor->pixelContentsRect());
return rect;
}
void BackingStorePrivate::setBackingStoreRect(const Platform::IntRect& backingStoreRect, double scale)
{
if (!m_webPage->isVisible())
return;
if (!isActive()) {
m_webPage->d->setShouldResetTilesWhenShown(true);
return;
}
if (m_suspendBackingStoreUpdates || m_suspendGeometryUpdates)
return;
Platform::IntRect oldBackingStoreRect = frontState()->backingStoreRect();
double currentScale = frontState()->scale();
if (backingStoreRect == oldBackingStoreRect && scale == currentScale)
return;
#if DEBUG_TILEMATRIX
Platform::logAlways(Platform::LogLevelCritical,
"BackingStorePrivate::setBackingStoreRect changed from %s to %s",
oldBackingStoreRect.toString().c_str(),
backingStoreRect.toString().c_str());
#endif
BackingStoreGeometry* oldGeometry = frontState();
TileMap oldTileMap = oldGeometry->tileMap();
TileIndexList indexesToFill = indexesForBackingStoreRect(backingStoreRect);
ASSERT(static_cast<int>(indexesToFill.size()) == oldTileMap.size());
m_renderQueue->clear(oldBackingStoreRect, RenderQueue::DontClearRegularRenderJobs);
m_renderQueue->backingStoreRectChanging(oldBackingStoreRect, backingStoreRect);
TileMap newTileMap;
TileMap leftOverTiles;
TileMap::const_iterator tileMapEnd = oldTileMap.end();
for (TileMap::const_iterator it = oldTileMap.begin(); it != tileMapEnd; ++it) {
TileIndex oldIndex = it->key;
TileBuffer* oldTileBuffer = it->value;
if (oldTileBuffer && backingStoreRect.contains(oldTileBuffer->lastRenderOrigin())) {
TileIndex newIndex = indexOfTile(oldTileBuffer->lastRenderOrigin(), backingStoreRect);
size_t i = indexesToFill.find(newIndex);
ASSERT(i != WTF::notFound);
indexesToFill.remove(i);
newTileMap.add(newIndex, oldTileBuffer);
} else {
leftOverTiles.add(oldIndex, oldTileBuffer);
}
}
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) {
TileBuffer* oldTileBuffer = it->value;
if (i >= indexesToFill.size()) {
ASSERT_NOT_REACHED();
break;
}
TileIndex newIndex = indexesToFill.at(i);
newTileMap.add(newIndex, oldTileBuffer);
++i;
}
ASSERT(oldTileMap.size() == newTileMap.size());
BackingStoreGeometry* newGeometry = new BackingStoreGeometry;
newGeometry->setScale(scale);
newGeometry->setNumberOfTilesWide(backingStoreRect.width() / tileWidth());
newGeometry->setNumberOfTilesHigh(backingStoreRect.height() / tileHeight());
newGeometry->setBackingStoreOffset(backingStoreRect.location());
newGeometry->setTileMap(newTileMap);
adoptAsFrontState(newGeometry);
updateTilesAfterBackingStoreRectChange();
}
void BackingStorePrivate::updateTilesAfterBackingStoreRectChange()
{
BackingStoreGeometry* geometry = frontState();
TileMap currentMap = geometry->tileMap();
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
TileIndex index = it->key;
TileBuffer* tileBuffer = it->value;
Platform::IntPoint tileOrigin = geometry->originOfTile(index);
Platform::IntRect rect(tileOrigin, tileSize());
if (geometry->isTileCorrespondingToBuffer(index, tileBuffer)) {
if (m_renderQueue->regularRenderJobsPreviouslyAttemptedButNotRendered(rect)) {
Platform::IntRectRegion tileNotRenderedRegion = Platform::IntRectRegion::intersectRegions(m_renderQueue->regularRenderJobsNotRenderedRegion(), rect);
clearAndUpdateTileOfNotRenderedRegion(index, tileBuffer, tileNotRenderedRegion, geometry);
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelCritical,
"BackingStorePrivate::updateTilesAfterBackingStoreRectChange did clear tile %s",
tileNotRenderedRegion.extents().toString().c_str());
#endif
} else {
if (!tileBuffer || (!tileBuffer->isRendered(tileVisibleContentsRect(index, geometry), geometry->scale())
&& !isCurrentVisibleJob(index, geometry)))
updateTile(tileOrigin, false );
}
} else if (rect.intersects(expandedContentsRect()))
updateTile(tileOrigin, false );
}
}
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;
}
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&, TileBuffer* tileBuffer,
const Platform::IntRectRegion& tileNotRenderedRegion,
BackingStoreGeometry*,
bool update)
{
if (tileNotRenderedRegion.isEmpty())
return;
m_renderQueue->clear(tileNotRenderedRegion, RenderQueue::ClearAnyJobs);
if (update) {
m_renderQueue->addToQueue(RenderQueue::RegularRender, tileNotRenderedRegion);
}
if (!tileBuffer)
return;
if (Platform::IntRectRegion::intersectRegions(tileBuffer->renderedRegion(), tileNotRenderedRegion).isEmpty())
return;
ASSERT(Platform::webKitThreadMessageClient()->isCurrentThread());
if (!Platform::webKitThreadMessageClient()->isCurrentThread())
return;
Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
Platform::createMethodCallMessage(&BackingStorePrivate::clearRenderedRegion,
this, tileBuffer, tileNotRenderedRegion));
}
void BackingStorePrivate::clearRenderedRegion(TileBuffer* tileBuffer, const Platform::IntRectRegion& region)
{
ASSERT(Platform::userInterfaceThreadMessageClient()->isCurrentThread());
if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread())
return;
if (!tileBuffer)
return;
tileBuffer->clearRenderedRegion(region);
}
bool BackingStorePrivate::isCurrentVisibleJob(const TileIndex& index, BackingStoreGeometry* geometry) const
{
return m_renderQueue->isCurrentVisibleZoomJob(index)
|| m_renderQueue->isCurrentVisibleScrollJob(index)
|| m_renderQueue->isCurrentVisibleZoomJobCompleted(index)
|| m_renderQueue->isCurrentVisibleScrollJobCompleted(index)
|| m_renderQueue->isCurrentRegularRenderJob(index, geometry);
}
Platform::IntRect BackingStorePrivate::nonOverscrolled(const Platform::IntRect& viewportRect, const Platform::IntRect& contentsRect)
{
const Platform::IntPoint maximumReasonableViewportLocation(
contentsRect.right() - viewportRect.width(),
contentsRect.bottom() - viewportRect.height());
const Platform::IntPoint minimumRectLocation(
std::max(0, std::min(maximumReasonableViewportLocation.x(), viewportRect.x())),
std::max(0, std::min(maximumReasonableViewportLocation.y(), viewportRect.y())));
return Platform::IntRect(minimumRectLocation, viewportRect.size());
}
Platform::IntRect BackingStorePrivate::enclosingTileRect(const Platform::IntRect& pixelContentsRect)
{
Platform::IntPoint location(
tileWidth() * (pixelContentsRect.x() / tileWidth()),
tileHeight() * (pixelContentsRect.y() / tileHeight()));
return Platform::IntRect(location, Platform::IntSize(
tileWidth() * ((pixelContentsRect.right() - location.x() - 1) / tileWidth() + 1),
tileHeight() * ((pixelContentsRect.bottom() - location.y() - 1) / tileHeight() + 1)));
}
Platform::IntRect BackingStorePrivate::desiredBackingStoreRect(const Platform::IntRect& pixelViewportRect, const Platform::IntRect& maximumReasonableRect, int deltaX, int deltaY)
{
const int scrollDeltaCutoff = 30;
const float multiplierDownAtStandstill = 2.0f;
Platform::IntRect desiredRect = pixelViewportRect;
desiredRect.inflate(tileWidth() / 2, tileHeight() / 2);
desiredRect.intersect(maximumReasonableRect);
const float expandX = std::max(-scrollDeltaCutoff, std::min(scrollDeltaCutoff, -deltaX)) / static_cast<float>(scrollDeltaCutoff);
const float expandY = std::max(-scrollDeltaCutoff, std::min(scrollDeltaCutoff, -deltaY)) / static_cast<float>(scrollDeltaCutoff);
const float momentum = std::max(expandX, expandY);
const float viewportRatio = pixelViewportRect.isEmpty() ? 1.0f : (pixelViewportRect.width() / static_cast<float>(pixelViewportRect.height()));
const float viewportRatioMultiplier = viewportRatio + momentum * (1.0f - viewportRatio);
const float multiplierDown = multiplierDownAtStandstill + momentum * (1.0f - multiplierDownAtStandstill);
float importanceX = desiredRect.width() == maximumReasonableRect.width() ? 0.0f : (1.0f - fabs(expandY));
float importanceY = desiredRect.height() == maximumReasonableRect.height() ? 0.0f : (1.0f - fabs(expandX));
if (importanceX <= FLT_EPSILON && importanceY <= FLT_EPSILON) {
importanceX = 1.0f;
importanceY = 1.0f;
}
importanceX *= viewportRatioMultiplier;
const float multiplierX = importanceY ? (importanceX / importanceY) : 1.0f;
const float multiplierY = importanceX ? (importanceY / importanceX) : 1.0f;
float expandRight = (0.5f + (0.4f * expandX)) * multiplierX;
float expandLeft = (0.5f + (-0.4f * expandX)) * multiplierX;
float expandDown = (0.5f + (0.4f * expandY)) * multiplierY * multiplierDown;
float expandUp = (0.5f + (-0.4f * expandY)) * multiplierY;
int remainingNumberOfTilePixels =
SurfacePool::globalSurfacePool()->numberOfBackingStoreFrontBuffers() * tileWidth() * tileHeight()
- desiredRect.area();
while (expandRight > FLT_EPSILON || expandLeft > FLT_EPSILON || expandDown > FLT_EPSILON || expandUp > FLT_EPSILON) {
int previousRemainingNumberOfTilePixels = remainingNumberOfTilePixels;
const int p = remainingNumberOfTilePixels;
const int w = desiredRect.width();
const int h = desiredRect.height();
const float r = expandRight;
const float l = expandLeft;
const float d = expandDown;
const float u = expandUp;
int pxLeft = 0;
int pxRight = 0;
int pxDown = 0;
int pxUp = 0;
if (l + r <= FLT_EPSILON) { ASSERT(d + u > FLT_EPSILON);
const float c = p / (w * (d + u));
pxDown = static_cast<int>(c * expandDown);
pxUp = static_cast<int>(c * expandUp);
} else if (u + d <= FLT_EPSILON) { ASSERT(l + r > FLT_EPSILON);
const float c = p / (h * (l + r));
pxLeft = static_cast<int>(c * expandLeft);
pxRight = static_cast<int>(c * expandRight);
} else {
const float c = (sqrt(pow(w * (d + u) + h * (l + r), 2.0) + 4.0f * p * (d + u) * (l + r)) - w * (d + u) - h * (l + r)) / (2.0f * (d + u) * (l + r));
pxRight = static_cast<int>(c * expandRight);
pxLeft = static_cast<int>(c * expandLeft);
pxDown = static_cast<int>(c * expandDown);
pxUp = static_cast<int>(c * expandUp);
}
desiredRect.setX(desiredRect.x() - pxLeft);
desiredRect.setWidth(desiredRect.width() + pxLeft + pxRight);
desiredRect.setY(desiredRect.y() - pxUp);
desiredRect.setHeight(desiredRect.height() + pxUp + pxDown);
if (desiredRect.right() >= maximumReasonableRect.right())
expandRight = 0.0f;
if (desiredRect.x() >= maximumReasonableRect.x())
expandLeft = 0.0f;
if (desiredRect.bottom() >= maximumReasonableRect.bottom())
expandDown = 0.0f;
if (desiredRect.y() >= maximumReasonableRect.y())
expandUp = 0.0f;
desiredRect.intersect(maximumReasonableRect);
remainingNumberOfTilePixels =
SurfacePool::globalSurfacePool()->numberOfBackingStoreFrontBuffers() * tileWidth() * tileHeight()
- desiredRect.area();
if (previousRemainingNumberOfTilePixels == remainingNumberOfTilePixels)
break;
}
return desiredRect;
}
void BackingStorePrivate::mergeDesiredBackingStoreRect(const Platform::IntRect& desiredRect, const Platform::IntRect& pixelViewportForDesiredRect)
{
double currentScale = m_webPage->d->currentScale();
if (m_desiredBackingStoreRect.isEmpty() || m_desiredBackingStoreRectScale != currentScale)
m_desiredBackingStoreRect = desiredRect;
else {
Platform::IntRect previousRectAtCurrentLocation = m_desiredBackingStoreRect;
previousRectAtCurrentLocation.move(
-m_desiredBackingStoreRectViewportLocation.x() + pixelViewportForDesiredRect.x(),
-m_desiredBackingStoreRectViewportLocation.y() + pixelViewportForDesiredRect.y());
Platform::IntPoint location(
(desiredRect.x() + previousRectAtCurrentLocation.x() + 1) / 2,
(desiredRect.y() + previousRectAtCurrentLocation.y() + 1) / 2);
Platform::IntPoint bottomRight(
(desiredRect.right() + previousRectAtCurrentLocation.right() + 1) / 2,
(desiredRect.bottom() + previousRectAtCurrentLocation.bottom() + 1) / 2);
m_desiredBackingStoreRect = Platform::IntRect(location,
Platform::IntSize(bottomRight.x() - location.x(), bottomRight.y() - location.y()));
}
m_desiredBackingStoreRectScale = currentScale;
m_desiredBackingStoreRectViewportLocation = pixelViewportForDesiredRect.location();
}
Platform::IntRect BackingStorePrivate::largestTileRectForDesiredRect(const Platform::IntRect& minimumRect, const Platform::IntRect& desiredRect)
{
SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
ASSERT(!surfacePool->isEmpty());
static DivisorList divisorList = divisors(surfacePool->numberOfBackingStoreFrontBuffers());
const Platform::IntRect minimumTileRect = enclosingTileRect(minimumRect);
const Divisor minimumTileRectDivisor(minimumTileRect.width() / tileWidth(), minimumTileRect.height() / tileHeight());
Divisor bestRectDivisor;
bool bestRectContainsMinimumRect = false;
int bestRectArea = 0;
int bestRectDistanceFromMinimumRect = 0;
Platform::IntRect bestBackingStoreRect;
for (size_t i = 0; i < divisorList.size(); ++i) {
Divisor divisor = divisorList[i];
int remainingTilesX = std::max(0, divisor.first - minimumTileRectDivisor.first);
int remainingTilesY = std::max(0, divisor.second - minimumTileRectDivisor.second);
Platform::IntSize divisorBackingStoreRectSize(divisor.first * tileWidth(), divisor.second * tileHeight());
for (int dy = 0; dy <= remainingTilesY; ++dy) {
for (int dx = 0; dx <= remainingTilesX; ++dx) {
const Platform::IntRect possibleBackingStoreRect(
Platform::IntPoint(minimumTileRect.x() - dx * tileWidth(), minimumTileRect.y() - dy * tileHeight()),
divisorBackingStoreRectSize);
Platform::IntRect relevantRect = possibleBackingStoreRect;
relevantRect.intersect(desiredRect);
int area = relevantRect.area();
bool betterThanPreviousRect = false;
bool containsMinimumRect = possibleBackingStoreRect.contains(minimumRect);
int distanceFromMinimumRect = bestRectDistanceFromMinimumRect - 1;
if (!bestRectArea) betterThanPreviousRect = true;
if (!bestRectContainsMinimumRect && containsMinimumRect)
betterThanPreviousRect = true;
if (bestRectContainsMinimumRect && area > bestRectArea)
betterThanPreviousRect = true;
if (bestRectContainsMinimumRect && area == bestRectArea) {
distanceFromMinimumRect = std::min(
minimumRect.x() - possibleBackingStoreRect.x(),
minimumRect.y() - possibleBackingStoreRect.y());
distanceFromMinimumRect = std::min(distanceFromMinimumRect, std::min(
possibleBackingStoreRect.right() - minimumRect.right(),
possibleBackingStoreRect.bottom() - minimumRect.bottom()));
if (distanceFromMinimumRect > bestRectDistanceFromMinimumRect)
betterThanPreviousRect = true;
}
if (bestRectContainsMinimumRect && area == bestRectArea && distanceFromMinimumRect == bestRectDistanceFromMinimumRect) {
if (possibleBackingStoreRect.y() > bestBackingStoreRect.y())
betterThanPreviousRect = true;
else if (possibleBackingStoreRect.y() == bestBackingStoreRect.y() && possibleBackingStoreRect.x() > bestBackingStoreRect.x())
betterThanPreviousRect = true;
}
#if DEBUG_TILEMATRIX
Platform::logAlways(Platform::LogLevelCritical,
"Desired rect %s: Potential rect %s (%dx%d) is %s than previous best rect %s (%dx%d). Area: %d vs. %d. Distance: %d vs. %d.",
desiredRect.toString().c_str(),
possibleBackingStoreRect.toString().c_str(),
divisor.first, divisor.second,
betterThanPreviousRect ? "better" : "worse",
bestBackingStoreRect.toString().c_str(),
bestRectDivisor.first, bestRectDivisor.second,
area, bestRectArea,
distanceFromMinimumRect, bestRectDistanceFromMinimumRect);
#endif
if (betterThanPreviousRect) {
bestRectDivisor = divisor;
bestRectContainsMinimumRect = containsMinimumRect;
bestRectArea = area;
bestRectDistanceFromMinimumRect = distanceFromMinimumRect;
bestBackingStoreRect = possibleBackingStoreRect;
}
}
}
}
return bestBackingStoreRect;
}
void BackingStorePrivate::scrollBackingStore(int deltaX, int deltaY)
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
if (!m_webPage->isVisible())
return;
if (!isActive()) {
m_webPage->d->setShouldResetTilesWhenShown(true);
return;
}
Platform::ViewportAccessor* viewportAccessor = m_webPage->webkitThreadViewportAccessor();
Platform::IntRect pixelContentsRect = expandedContentsRect();
Platform::IntRect nonOverscrolledPixelViewportRect = nonOverscrolled(viewportAccessor->pixelViewportRect(), pixelContentsRect);
const Platform::IntRect maximumReasonableRect = enclosingTileRect(pixelContentsRect);
Platform::IntRect desiredRect = desiredBackingStoreRect(nonOverscrolledPixelViewportRect, maximumReasonableRect, deltaX, deltaY);
mergeDesiredBackingStoreRect(desiredRect, nonOverscrolledPixelViewportRect);
const Platform::IntRect backingStoreRect = largestTileRectForDesiredRect(nonOverscrolledPixelViewportRect, m_desiredBackingStoreRect);
#if DEBUG_TILEMATRIX
Platform::logAlways(Platform::LogLevelCritical,
"BackingStorePrivate::scrollBackingStore nonOverscrolledPixelViewportRect=%s, desiredRect=%s, pixelContentsRect=%s, maximumReasonableRect=%s, backingStoreRect=%s",
nonOverscrolledPixelViewportRect.toString().c_str(),
m_desiredBackingStoreRect.toString().c_str(),
pixelContentsRect.toString().c_str(),
maximumReasonableRect.toString().c_str(),
backingStoreRect.toString().c_str());
#endif
ASSERT(!backingStoreRect.isEmpty());
setBackingStoreRect(backingStoreRect, m_desiredBackingStoreRectScale);
}
TileIndexList BackingStorePrivate::render(const TileIndexList& tileIndexList)
{
if (!m_webPage->isVisible())
return TileIndexList();
requestLayoutIfNeeded();
if (!isActive())
return TileIndexList();
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelInfo,
"BackingStorePrivate::render %d tiles, m_suspendBackingStoreUpdates = %s",
tileIndexList.size(),
m_suspendBackingStoreUpdates ? "true" : "false");
#endif
ASSERT(!m_tileMatrixNeedsUpdate);
if (tileIndexList.isEmpty())
return tileIndexList;
Platform::ViewportAccessor* viewportAccessor = m_webPage->webkitThreadViewportAccessor();
BackingStoreGeometry* geometry = frontState();
TileMap oldTileMap = geometry->tileMap();
double currentScale = geometry->scale();
BackingStoreGeometry* newGeometry = new BackingStoreGeometry;
newGeometry->setScale(geometry->scale());
newGeometry->setNumberOfTilesWide(geometry->numberOfTilesWide());
newGeometry->setNumberOfTilesHigh(geometry->numberOfTilesHigh());
newGeometry->setBackingStoreOffset(geometry->backingStoreOffset());
TileMap newTileMap(oldTileMap); TileIndexList renderedTiles;
for (size_t i = 0; i < tileIndexList.size(); ++i) {
if (!SurfacePool::globalSurfacePool()->numberOfAvailableBackBuffers()) {
newGeometry->setTileMap(newTileMap);
adoptAsFrontState(newGeometry);
geometry = frontState();
newGeometry = new BackingStoreGeometry;
newGeometry->setScale(geometry->scale());
newGeometry->setNumberOfTilesWide(geometry->numberOfTilesWide());
newGeometry->setNumberOfTilesHigh(geometry->numberOfTilesHigh());
newGeometry->setBackingStoreOffset(geometry->backingStoreOffset());
}
TileIndex index = tileIndexList[i];
Platform::IntPoint tileOrigin = newGeometry->originOfTile(index);
Platform::IntRect dirtyRect(tileOrigin, tileSize());
if (!expandedContentsRect().isEmpty()) {
dirtyRect.intersect(expandedContentsRect());
if (dirtyRect.isEmpty()) {
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelInfo,
"BackingStorePrivate::render skipping tile at %s, it's outside the expanded contents rect of %s",
newGeometry->originOfTile(index).toString().c_str(),
expandedContentsRect().toString().c_str());
#endif
continue;
}
}
TileBuffer* backBuffer = SurfacePool::globalSurfacePool()->takeBackBuffer();
ASSERT(backBuffer);
backBuffer->paintBackground();
backBuffer->setLastRenderScale(currentScale);
backBuffer->setLastRenderOrigin(tileOrigin);
backBuffer->clearRenderedRegion();
BlackBerry::Platform::Graphics::Buffer* nativeBuffer = backBuffer->nativeBuffer();
BlackBerry::Platform::Graphics::setBufferOpaqueHint(nativeBuffer, !Color(m_webPage->settings()->backgroundColor()).hasAlpha());
if (isOpenGLCompositing())
SurfacePool::globalSurfacePool()->waitForBuffer(backBuffer);
const Platform::FloatPoint documentDirtyRectOrigin = viewportAccessor->toDocumentContents(dirtyRect.location(), currentScale);
const Platform::IntRect dstRect(dirtyRect.location() - tileOrigin, dirtyRect.size());
if (!renderContents(nativeBuffer, dstRect, currentScale, documentDirtyRectOrigin, RenderRootLayer))
continue;
backBuffer->addRenderedRegion(dirtyRect);
renderedTiles.append(index);
newTileMap.set(index, backBuffer);
}
m_renderQueue->clear(renderedTiles, frontState(), RenderQueue::DontClearCompletedJobs);
updateSuspendScreenUpdateState();
newGeometry->setTileMap(newTileMap);
adoptAsFrontState(newGeometry);
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelInfo,
"BackingStorePrivate::render done rendering %d tiles.",
renderedTiles.size());
#endif
return renderedTiles;
}
void BackingStorePrivate::requestLayoutIfNeeded() const
{
m_webPage->d->updateLayoutAndStyleIfNeededRecursive();
}
void BackingStorePrivate::renderAndBlitVisibleContentsImmediately()
{
renderAndBlitImmediately(visibleContentsRect());
}
void BackingStorePrivate::renderAndBlitImmediately(const Platform::IntRect& rect)
{
updateTileMatrixIfNeeded();
m_renderQueue->addToQueue(RenderQueue::VisibleZoom, rect);
renderJob();
}
void BackingStorePrivate::blitVisibleContents(bool force)
{
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
BlackBerry::Platform::createMethodCallMessage(
&BackingStorePrivate::blitVisibleContents, this, force));
return;
}
if (m_suspendScreenUpdatesUserInterfaceThread) {
if (force)
m_hasBlitJobs = false;
return;
}
if (!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;
Platform::ViewportAccessor* viewportAccessor = m_webPage->client()->userInterfaceViewportAccessor();
if (!viewportAccessor)
return;
const Platform::IntRect dstRect = viewportAccessor->destinationSurfaceRect();
if (dstRect.isEmpty())
return;
BlackBerry::Platform::PerformanceMonitor::instance()->reportFrameRenderBegin();
const Platform::IntRect pixelViewportRect = viewportAccessor->pixelViewportRect();
const Platform::FloatRect documentViewportRect = viewportAccessor->documentFromPixelContents(pixelViewportRect);
Platform::IntRect pixelSrcRect = pixelViewportRect;
Platform::FloatRect documentSrcRect = documentViewportRect;
#if DEBUG_VISUALIZE
Platform::ViewportAccessor* debugViewportAccessor = new BackingStoreVisualizationViewportAccessor(viewportAccessor, this);
if (isActive()) {
viewportAccessor = debugViewportAccessor;
documentSrcRect = debugViewportAccessor->documentViewportRect();
pixelSrcRect = debugViewportAccessor->pixelViewportRect();
}
#endif
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelCritical,
"BackingStorePrivate::blitVisibleContents(): dstRect=%s, documentSrcRect=%s, scale=%f",
dstRect.toString().c_str(), documentSrcRect.toString().c_str(), viewportAccessor->scale());
#endif
BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
ASSERT(dstBuffer);
if (dstBuffer) {
BlackBerry::Platform::Graphics::clearBuffer(dstBuffer,
m_webPageBackgroundColor.red(), m_webPageBackgroundColor.green(),
m_webPageBackgroundColor.blue(), m_webPageBackgroundColor.alpha());
} else
Platform::logAlways(Platform::LogLevelWarn, "Empty window buffer, can't blit contents.");
Vector<TileBuffer*> blittedTiles;
if (isActive() && !m_webPage->d->compositorDrawsRootLayer()) {
BackingStoreGeometry* geometry = frontState();
TileMap currentMap = geometry->tileMap();
double currentScale = geometry->scale();
const Platform::IntRect transformedContentsRect = currentScale == viewportAccessor->scale()
? viewportAccessor->pixelContentsRect()
: viewportAccessor->roundFromDocumentContents(viewportAccessor->documentContentsRect(), currentScale);
const Platform::IntRect transformedSrcRect = currentScale == viewportAccessor->scale()
? pixelSrcRect
: viewportAccessor->roundFromDocumentContents(documentSrcRect, currentScale);
Platform::IntRect clippedTransformedSrcRect = transformedSrcRect;
const Platform::IntPoint origin = transformedSrcRect.location();
TransformationMatrix transformation;
if (!transformedSrcRect.isEmpty())
transformation = TransformationMatrix::rectToRect(FloatRect(FloatPoint(0.0, 0.0), WebCore::IntSize(transformedSrcRect.size())), WebCore::IntRect(dstRect));
Platform::Graphics::PlatformGraphicsContext* destinationContext = lockBufferDrawable(dstBuffer);
if (!destinationContext)
Platform::logAlways(Platform::LogLevelWarn, "Could not lock drawable for the destination buffer, not drawing checkerboard.");
else {
if (!BlackBerry::Platform::Settings::isPublicBuild()) {
Platform::Graphics::AffineTransform srcTransform;
srcTransform.scale(transformation.a());
destinationContext->addPredefinedPattern(
viewportAccessor->pixelViewportFromContents(viewportAccessor->pixelContentsRect()),
Platform::Graphics::Checkerboard, srcTransform);
}
releaseBufferDrawable(dstBuffer);
}
TileRectList tileRectList = mapFromPixelContentsToTiles(clippedTransformedSrcRect, geometry);
for (size_t i = 0; i < tileRectList.size(); ++i) {
TileRect tileRect = tileRectList[i];
TileIndex index = tileRect.first;
Platform::IntRect dirtyRect = tileRect.second;
if (!transformedContentsRect.isEmpty()) {
dirtyRect.intersect(transformedContentsRect);
}
if (dirtyRect.isEmpty())
continue;
dirtyRect.move(-origin.x(), -origin.y());
TileBuffer* tileBuffer = currentMap.get(index);
if (geometry->isTileCorrespondingToBuffer(index, tileBuffer)) {
Platform::IntRectRegion renderedRegion = tileBuffer->renderedRegion();
std::vector<Platform::IntRect> dirtyRenderedRects = renderedRegion.rects();
for (size_t j = 0; j < dirtyRenderedRects.size(); ++j) {
const Platform::IntRect& dirtyRenderedRect = intersection(tileRect.second, dirtyRenderedRects.at(j));
if (dirtyRenderedRect.isEmpty())
continue;
blitTileRect(tileBuffer, dirtyRenderedRect, origin, transformation, geometry);
}
blittedTiles.append(tileBuffer);
}
}
}
if (isOpenGLCompositing())
SurfacePool::globalSurfacePool()->notifyBuffersComposited(blittedTiles);
#if USE(ACCELERATED_COMPOSITING)
if (WebPageCompositorPrivate* compositor = m_webPage->d->compositor())
compositor->drawLayers(dstRect, documentSrcRect);
#endif
const Platform::IntRect pixelContentsRect = viewportAccessor->pixelContentsRect();
Platform::IntRectRegion overScrollRegion = Platform::IntRectRegion::subtractRegions(
dstRect, viewportAccessor->pixelViewportFromContents(pixelContentsRect));
if (!overScrollRegion.isEmpty()) {
Platform::Graphics::PlatformGraphicsContext* destinationContext = lockBufferDrawable(dstBuffer);
if (!destinationContext)
Platform::logAlways(Platform::LogLevelWarn, "Could not lock drawable for the destination buffer, not drawing overscroll.");
else {
std::vector<Platform::IntRect> overScrollRects = overScrollRegion.rects();
for (size_t i = 0; i < overScrollRects.size(); ++i) {
const Platform::IntRect& overScrollRect = overScrollRects.at(i);
if (m_webPage->settings()->isEnableDefaultOverScrollBackground()) {
Platform::Graphics::AffineTransform srcTransform;
srcTransform.translate(-overScrollRect.x(), -overScrollRect.y());
destinationContext->addPredefinedPattern(overScrollRect, Platform::Graphics::Overscroll, srcTransform);
} else {
destinationContext->setFillColor(m_webPage->settings()->overScrollColor());
destinationContext->addFillRect(overScrollRect);
}
}
releaseBufferDrawable(dstBuffer);
}
}
#if DEBUG_VISUALIZE
if (debugViewportAccessor) {
Platform::Graphics::PlatformGraphicsContext* destinationContext = lockBufferDrawable(dstBuffer);
if (!destinationContext)
Platform::logAlways(Platform::LogLevelWarn, "Could not lock drawable for the destination buffer, not drawing viewport debug rects.");
else {
destinationContext->save();
Platform::FloatRect wkViewport = debugViewportAccessor->roundToPixelFromDocumentContents(Platform::IntRect(m_client->visibleContentsRect()));
Platform::FloatRect uiViewport = debugViewportAccessor->roundToPixelFromDocumentContents(documentViewportRect);
wkViewport.move(-pixelSrcRect.x(), -pixelSrcRect.y());
uiViewport.move(-pixelSrcRect.x(), -pixelSrcRect.y());
wkViewport.inflate(-0.5, -0.5);
uiViewport.inflate(-0.5, -0.5);
destinationContext->setStrokeColor(0xff0000ff);
destinationContext->addStrokeRect(wkViewport, 1.0);
destinationContext->setStrokeColor(0x0000ffff);
destinationContext->addStrokeRect(uiViewport, 1.0);
destinationContext->restore();
releaseBufferDrawable(dstBuffer);
}
delete debugViewportAccessor;
}
#endif
m_webPage->client()->postToSurface(dstRect);
BlackBerry::Platform::PerformanceMonitor::instance()->reportFrameRenderEnd(true );
}
#if USE(ACCELERATED_COMPOSITING)
void BackingStorePrivate::compositeContents(WebCore::LayerRenderer* layerRenderer, const WebCore::TransformationMatrix& transform, const WebCore::FloatRect& documentContents, bool contentsOpaque)
{
Platform::ViewportAccessor* viewportAccessor = m_webPage->client()->userInterfaceViewportAccessor();
if (!viewportAccessor)
return;
Platform::IntRect pixelContents = viewportAccessor->roundToPixelFromDocumentContents(documentContents);
pixelContents.intersect(viewportAccessor->pixelContentsRect());
if (pixelContents.isEmpty())
return;
if (!isActive())
return;
if (m_webPage->d->compositorDrawsRootLayer())
return;
BackingStoreGeometry* geometry = frontState();
TileMap currentMap = geometry->tileMap();
Vector<TileBuffer*> compositedTiles;
Platform::IntRectRegion pixelContentsRegion = pixelContents;
Platform::IntRectRegion backingStoreRegion = geometry->backingStoreRect();
Platform::IntRectRegion clearRegion = Platform::IntRectRegion::subtractRegions(pixelContentsRegion, backingStoreRegion);
Color clearColor(Color::white);
std::vector<Platform::IntRect> clearRects = clearRegion.rects();
for (size_t i = 0; i < clearRects.size(); ++i)
layerRenderer->drawColor(transform, viewportAccessor->documentFromPixelContents(clearRects.at(i)), clearColor);
TileRectList tileRectList = mapFromPixelContentsToTiles(pixelContents, geometry);
for (size_t i = 0; i < tileRectList.size(); ++i) {
TileRect tileRect = tileRectList[i];
TileIndex index = tileRect.first;
Platform::IntRect dirtyRect = tileRect.second;
TileBuffer* tileBuffer = currentMap.get(index);
if (!tileBuffer || !geometry->isTileCorrespondingToBuffer(index, tileBuffer))
layerRenderer->drawColor(transform, viewportAccessor->documentFromPixelContents(dirtyRect), clearColor);
else {
Platform::IntPoint tileOrigin = tileBuffer->lastRenderOrigin();
Platform::FloatRect tileDocumentContentsRect = viewportAccessor->documentFromPixelContents(tileBuffer->pixelContentsRect());
layerRenderer->compositeBuffer(transform, tileDocumentContentsRect, tileBuffer->nativeBuffer(), contentsOpaque, 1.0f);
compositedTiles.append(tileBuffer);
Platform::IntRectRegion notRenderedRegion = Platform::IntRectRegion::subtractRegions(dirtyRect, tileBuffer->renderedRegion());
std::vector<Platform::IntRect> notRenderedRects = notRenderedRegion.rects();
for (size_t i = 0; i < notRenderedRects.size(); ++i) {
Platform::IntRect tileSurfaceRect = notRenderedRects.at(i);
tileSurfaceRect.move(-tileOrigin.x(), -tileOrigin.y());
layerRenderer->drawColor(transform, viewportAccessor->documentFromPixelContents(tileSurfaceRect), clearColor);
}
}
}
SurfacePool::globalSurfacePool()->notifyBuffersComposited(compositedTiles);
}
#endif
Platform::IntRect BackingStorePrivate::blitTileRect(TileBuffer* tileBuffer,
const Platform::IntRect& tilePixelContentsRect,
const Platform::IntPoint& origin,
const WebCore::TransformationMatrix& matrix,
BackingStoreGeometry*)
{
if (!m_webPage->isVisible() || !isActive() || !tileBuffer)
return Platform::IntRect();
Platform::IntRect srcRect = tilePixelContentsRect;
Platform::IntPoint tileOrigin = tileBuffer->lastRenderOrigin();
srcRect.move(-tileOrigin.x(), -tileOrigin.y());
Platform::IntRect dstRect = tilePixelContentsRect;
dstRect.move(-origin.x(), -origin.y());
dstRect = matrix.mapRect(dstRect);
if (!matrix.isIdentity()) {
dstRect.intersect(Platform::IntRect(Platform::IntPoint(0, 0), surfaceSize()));
}
ASSERT(!dstRect.isEmpty());
ASSERT(!srcRect.isEmpty());
if (dstRect.isEmpty() || srcRect.isEmpty())
return Platform::IntRect();
blitToWindow(dstRect, tileBuffer->nativeBuffer(), srcRect, BlackBerry::Platform::Graphics::SourceCopy, 255);
return dstRect;
}
bool BackingStorePrivate::isTileVisible(const TileIndex& index, BackingStoreGeometry* geometry) const
{
return isTileVisible(geometry->originOfTile(index));
}
bool BackingStorePrivate::isTileVisible(const Platform::IntPoint& origin) const
{
return Platform::IntRect(origin, tileSize()).intersects(visibleContentsRect());
}
TileIndexList BackingStorePrivate::visibleTileIndexes(BackingStoreGeometry* geometry) const
{
TileMap tileMap = geometry->tileMap();
TileIndexList visibleTiles;
TileMap::const_iterator end = tileMap.end();
for (TileMap::const_iterator it = tileMap.begin(); it != end; ++it) {
Platform::IntRect tilePixelContentsRect(geometry->originOfTile(it->key), tileSize());
if (tilePixelContentsRect.intersects(visibleContentsRect()))
visibleTiles.append(it->key);
}
return visibleTiles;
}
Platform::IntRect BackingStorePrivate::tileVisibleContentsRect(const TileIndex& index, BackingStoreGeometry* geometry) const
{
if (!isTileVisible(index, geometry))
return Platform::IntRect();
return tileContentsRect(index, visibleContentsRect(), geometry);
}
Platform::IntRect BackingStorePrivate::tileContentsRect(const TileIndex& index, const Platform::IntRect& pixelContentsRect, BackingStoreGeometry* state) const
{
TileRectList tileRectList = mapFromPixelContentsToTiles(pixelContentsRect, 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::resetTiles()
{
BackingStoreGeometry* geometry = frontState();
m_renderQueue->clear(geometry->backingStoreRect(), RenderQueue::ClearAnyJobs);
BackingStoreGeometry* newGeometry = new BackingStoreGeometry;
newGeometry->setScale(geometry->scale());
newGeometry->setNumberOfTilesWide(geometry->numberOfTilesWide());
newGeometry->setNumberOfTilesHigh(geometry->numberOfTilesHigh());
newGeometry->setBackingStoreOffset(geometry->backingStoreOffset());
TileMap currentMap = geometry->tileMap();
TileMap newTileMap;
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it)
newTileMap.add(it->key, 0);
newGeometry->setTileMap(newTileMap);
adoptAsFrontState(newGeometry); }
void BackingStorePrivate::updateTiles(bool updateVisible, bool immediate)
{
if (!isActive())
return;
BackingStoreGeometry* geometry = frontState();
TileMap currentMap = geometry->tileMap();
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
bool isVisible = isTileVisible(it->key, geometry);
if (!updateVisible && isVisible)
continue;
updateTile(geometry->originOfTile(it->key), immediate);
}
}
void BackingStorePrivate::updateTilesForScrollOrNotRenderedRegion(bool checkLoading)
{
BackingStoreGeometry* geometry = frontState();
TileMap currentMap = geometry->tileMap();
bool isLoading = m_client->loadState() == WebPagePrivate::Committed;
bool updateNonVisibleTiles = !checkLoading || !isLoading;
TileMap::const_iterator end = currentMap.end();
for (TileMap::const_iterator it = currentMap.begin(); it != end; ++it) {
TileIndex index = it->key;
TileBuffer* tileBuffer = it->value;
bool isVisible = isTileVisible(index, geometry);
Platform::IntPoint tileOrigin = geometry->originOfTile(index);
Platform::IntRect rect(tileOrigin, tileSize());
if (geometry->isTileCorrespondingToBuffer(index, tileBuffer)
&& m_renderQueue->regularRenderJobsPreviouslyAttemptedButNotRendered(rect)) {
if (isVisible) {
Platform::IntRectRegion tileNotRenderedRegion = Platform::IntRectRegion::intersectRegions(m_renderQueue->regularRenderJobsNotRenderedRegion(), rect);
clearAndUpdateTileOfNotRenderedRegion(index, tileBuffer, tileNotRenderedRegion, geometry, false );
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelCritical,
"BackingStorePrivate::updateTilesForScroll did clear tile %s",
tileNotRenderedRegion.extents().toString().c_str());
#endif
}
updateTile(tileOrigin, false );
} else if ((isVisible || updateNonVisibleTiles)
&& (!tileBuffer || !tileBuffer->isRendered(tileVisibleContentsRect(index, geometry), geometry->scale()))
&& !isCurrentVisibleJob(index, geometry))
updateTile(tileOrigin, false );
}
}
void BackingStorePrivate::updateTile(const Platform::IntPoint& origin, bool immediate)
{
if (!isActive())
return;
Platform::IntRect updateRect = Platform::IntRect(origin, tileSize());
if (immediate)
renderAndBlitImmediately(updateRect);
else {
RenderQueue::JobType jobType = isTileVisible(origin) ? RenderQueue::VisibleScroll : RenderQueue::NonVisibleScroll;
m_renderQueue->addToQueue(jobType, updateRect);
}
}
BackingStorePrivate::TileRectList BackingStorePrivate::mapFromPixelContentsToTiles(const Platform::IntRect& rect, BackingStoreGeometry* geometry) const
{
TileMap tileMap = geometry->tileMap();
TileRectList tileRectList;
TileMap::const_iterator end = tileMap.end();
for (TileMap::const_iterator it = tileMap.begin(); it != end; ++it) {
TileIndex index = it->key;
Platform::IntRect r = rect;
r.intersect(Platform::IntRect(geometry->originOfTile(index), tileSize()));
if (r.isEmpty())
continue;
TileRect tileRect;
tileRect.first = index;
tileRect.second = r;
tileRectList.append(tileRect);
}
return tileRectList;
}
void BackingStorePrivate::updateTileMatrixIfNeeded()
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
if (!m_tileMatrixNeedsUpdate)
return;
m_tileMatrixNeedsUpdate = false;
scrollBackingStore(0, 0);
}
void BackingStorePrivate::contentsSizeChanged(const Platform::IntSize&)
{
setTileMatrixNeedsUpdate();
updateTileMatrixIfNeeded();
}
void BackingStorePrivate::scrollChanged(const Platform::IntPoint&)
{
}
void BackingStorePrivate::transformChanged()
{
if (!m_webPage->isVisible())
return;
m_renderQueue->reset();
if (!isActive()) {
m_webPage->d->setShouldResetTilesWhenShown(true);
return;
}
resetTiles();
}
void BackingStorePrivate::orientationChanged()
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
setTileMatrixNeedsUpdate();
updateTileMatrixIfNeeded();
}
void BackingStorePrivate::actualVisibleSizeChanged(const Platform::IntSize&)
{
}
void BackingStorePrivate::createSurfaces()
{
BackingStoreGeometry* geometry = frontState();
TileMap initialMap = geometry->tileMap();
ASSERT(initialMap.isEmpty());
if (m_webPage->isVisible()) {
ASSERT_NOT_REACHED();
return;
}
updateSuspendScreenUpdateState();
SurfacePool* surfacePool = SurfacePool::globalSurfacePool();
surfacePool->initialize(tileSize());
if (surfacePool->isEmpty()) return;
DivisorList divisorList = divisors(surfacePool->numberOfBackingStoreFrontBuffers());
const Divisor divisor = divisorList[0];
int numberOfTilesWide = divisor.first;
int numberOfTilesHigh = divisor.second;
TileMap newTileMap;
for (int y = 0; y < numberOfTilesHigh; ++y) {
for (int x = 0; x < numberOfTilesWide; ++x) {
TileIndex index(x, y);
newTileMap.add(index, 0); }
}
BackingStoreGeometry* newGeometry = new BackingStoreGeometry;
newGeometry->setScale(m_webPage->d->currentScale());
newGeometry->setNumberOfTilesWide(divisor.first);
newGeometry->setNumberOfTilesHigh(divisor.second);
newGeometry->setTileMap(newTileMap);
adoptAsFrontState(newGeometry); }
Platform::IntPoint BackingStoreGeometry::originOfTile(const TileIndex& index) const
{
return Platform::IntPoint(backingStoreRect().x() + (index.i() * BackingStorePrivate::tileWidth()),
backingStoreRect().y() + (index.j() * BackingStorePrivate::tileHeight()));
}
int BackingStorePrivate::tileWidth()
{
return tileSize().width();
}
int BackingStorePrivate::tileHeight()
{
return tileSize().height();
}
Platform::IntSize BackingStorePrivate::tileSize()
{
static Platform::IntSize tileSize = Platform::Settings::instance()->tileSize();
return tileSize;
}
bool BackingStorePrivate::renderContents(BlackBerry::Platform::Graphics::Buffer* targetBuffer, const Platform::IntRect& dstRect, double scale, const Platform::FloatPoint& documentRenderOrigin, LayersToRender layersToRender) const
{
#if DEBUG_BACKINGSTORE
Platform::logAlways(Platform::LogLevelCritical,
"BackingStorePrivate::renderContents targetBuffer=0x%p dstRect=%s scale=%f documentRenderOrigin=%s",
targetBuffer, dstRect.toString().c_str(), scale, documentRenderOrigin.toString().c_str());
#endif
ASSERT(!m_webPage->d->mainFrame()->view()->needsLayout());
ASSERT(targetBuffer);
Platform::ViewportAccessor* viewportAccessor = m_webPage->webkitThreadViewportAccessor();
WebCore::FloatRect renderedFloatRect(documentRenderOrigin, viewportAccessor->toDocumentContents(dstRect.size(), scale));
WebCore::IntRect contentsRect(WebCore::IntPoint::zero(), m_client->contentsSize());
Color backgroundColor(m_webPage->settings()->backgroundColor());
if (contentsRect.isEmpty()
|| backgroundColor.hasAlpha()
|| !WebCore::FloatRect(contentsRect).contains(renderedFloatRect)) {
BlackBerry::Platform::Graphics::clearBuffer(targetBuffer, dstRect,
backgroundColor.red(), backgroundColor.green(),
backgroundColor.blue(), backgroundColor.alpha());
}
if (contentsRect.isEmpty())
return true;
Platform::Graphics::Drawable* bufferDrawable = Platform::Graphics::lockBufferDrawable(targetBuffer);
Platform::Graphics::Buffer* drawingBuffer = 0;
if (bufferDrawable)
drawingBuffer = targetBuffer;
else {
BBLOG(Platform::LogLevelWarn, "Using temporary buffer to paint contents, look into avoiding this.");
drawingBuffer = Platform::Graphics::createBuffer(dstRect.size(), Platform::Graphics::BackedWhenNecessary);
if (!drawingBuffer) {
Platform::logAlways(Platform::LogLevelWarn, "Could not create temporary buffer, expect bad things to happen.");
return false;
}
bufferDrawable = Platform::Graphics::lockBufferDrawable(drawingBuffer);
if (!bufferDrawable) {
Platform::logAlways(Platform::LogLevelWarn, "Could not lock temporary buffer drawable, expect bad things to happen.");
Platform::Graphics::destroyBuffer(drawingBuffer);
return false;
}
}
PlatformGraphicsContext* platformGraphicsContext = SurfacePool::globalSurfacePool()->createPlatformGraphicsContext(bufferDrawable);
ASSERT(platformGraphicsContext);
{
GraphicsContext graphicsContext(platformGraphicsContext);
graphicsContext.save();
graphicsContext.clip(dstRect);
if (targetBuffer == drawingBuffer)
graphicsContext.translate(-dstRect.x(), -dstRect.y());
graphicsContext.scale(WebCore::FloatSize(scale, scale));
graphicsContext.translate(-documentRenderOrigin.x(), -documentRenderOrigin.y());
WebCore::IntRect renderedRect = enclosingIntRect(renderedFloatRect);
renderedRect.intersect(contentsRect);
if (int leftOverFlow = m_client->frame()->view()->minimumScrollPosition().x()) {
renderedRect.move(leftOverFlow, 0);
graphicsContext.translate(-leftOverFlow, 0);
}
if (layersToRender == RenderRootLayer)
m_client->frame()->view()->paintContents(&graphicsContext, renderedRect);
else
m_client->frame()->view()->paintContentsForSnapshot(&graphicsContext, renderedRect, FrameView::ExcludeSelection, FrameView::DocumentCoordinates);
graphicsContext.restore();
}
SurfacePool::globalSurfacePool()->destroyPlatformGraphicsContext(platformGraphicsContext);
Platform::Graphics::releaseBufferDrawable(drawingBuffer);
if (targetBuffer != drawingBuffer) {
const Platform::IntRect srcRect(Platform::IntPoint::zero(), dstRect.size());
Platform::Graphics::blitToBuffer(targetBuffer, dstRect, drawingBuffer, srcRect);
Platform::Graphics::destroyBuffer(drawingBuffer);
}
return true;
}
#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 Platform::Graphics::Buffer* srcBuffer,
const Platform::IntRect& srcRect,
Platform::Graphics::BlendMode blendMode,
unsigned char globalAlpha)
{
ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
BlackBerry::Platform::Graphics::Buffer* dstBuffer = buffer();
ASSERT(dstBuffer);
ASSERT(srcBuffer);
if (!dstBuffer)
Platform::logAlways(Platform::LogLevelWarn, "Empty window buffer, couldn't blitToWindow");
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
}
WebCore::Color BackingStorePrivate::webPageBackgroundColorUserInterfaceThread() const
{
ASSERT(BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread());
return m_webPageBackgroundColor;
}
void BackingStorePrivate::setWebPageBackgroundColor(const WebCore::Color& color)
{
if (!BlackBerry::Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
typedef void (BlackBerry::WebKit::BackingStorePrivate::*FunctionType)(const WebCore::Color&);
BlackBerry::Platform::userInterfaceThreadMessageClient()->dispatchMessage(
BlackBerry::Platform::createMethodCallMessage<FunctionType, BackingStorePrivate, WebCore::Color>(
&BackingStorePrivate::setWebPageBackgroundColor, this, color));
return;
}
m_webPageBackgroundColor = color;
}
bool BackingStorePrivate::isScrollingOrZooming() const
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
return m_isScrollingOrZooming;
}
void BackingStorePrivate::setScrollingOrZooming(bool scrollingOrZooming, bool shouldBlit)
{
ASSERT(BlackBerry::Platform::webKitThreadMessageClient()->isCurrentThread());
if (m_isScrollingOrZooming == scrollingOrZooming)
return;
m_isScrollingOrZooming = scrollingOrZooming;
#if !ENABLE_REPAINTONSCROLL
m_suspendRenderJobs = scrollingOrZooming; #endif
if (!m_webPage->settings()->shouldRenderAnimationsOnScrollOrZoom())
m_suspendRegularRenderJobs = scrollingOrZooming;
m_webPage->d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(!scrollingOrZooming);
if (scrollingOrZooming)
m_renderQueue->setCurrentRegularRenderJobBatchUnderPressure(false);
#if ENABLE_SCROLLBARS
else if (shouldBlit)
blitVisibleContents();
#endif
if (!scrollingOrZooming && shouldPerformRegularRenderJobs())
dispatchRenderJob();
}
BackingStoreGeometry* BackingStorePrivate::frontState() const
{
return reinterpret_cast<BackingStoreGeometry*>(m_frontState);
}
void BackingStorePrivate::adoptAsFrontState(BackingStoreGeometry* newFrontState)
{
bool hasValidBuffers = false;
WTF::Vector<TileBuffer*> newTileBuffers;
TileMap newTileMap = newFrontState->tileMap();
TileMap::const_iterator end = newTileMap.end();
for (TileMap::const_iterator it = newTileMap.begin(); it != end; ++it) {
if (it->value) {
hasValidBuffers = true;
newTileBuffers.append(it->value);
}
}
if (!hasValidBuffers) {
m_tileMatrixContainsUsefulContent = false;
updateSuspendScreenUpdateState();
}
unsigned newFront = reinterpret_cast<unsigned>(newFrontState);
BackingStoreGeometry* oldFrontState = frontState();
_smp_xchg(&m_frontState, newFront);
bool hasSynced = false;
if (hasValidBuffers) {
m_tileMatrixContainsUsefulContent = true;
updateSuspendScreenUpdateState(&hasSynced);
}
if (!hasSynced) {
BlackBerry::Platform::userInterfaceThreadMessageClient()->syncToCurrentMessage();
}
TileMap oldTileMap = oldFrontState->tileMap();
end = oldTileMap.end();
for (TileMap::const_iterator it = oldTileMap.begin(); it != end; ++it) {
TileBuffer* tileBuffer = it->value;
if (tileBuffer && !newTileBuffers.contains(tileBuffer))
SurfacePool::globalSurfacePool()->addBackBuffer(tileBuffer);
}
delete oldFrontState;
}
void BackingStorePrivate::setCurrentBackingStoreOwner(WebPage* webPage)
{
if (BackingStorePrivate::s_currentBackingStoreOwner && BackingStorePrivate::s_currentBackingStoreOwner != webPage)
BackingStorePrivate::s_currentBackingStoreOwner->d->m_backingStore->d->resetTiles();
BackingStorePrivate::s_currentBackingStoreOwner = webPage;
if (webPage)
webPage->backingStore()->d->updateSuspendScreenUpdateState(); }
bool BackingStorePrivate::isActive() const
{
return BackingStorePrivate::s_currentBackingStoreOwner == m_webPage && SurfacePool::globalSurfacePool()->isActive();
}
void BackingStorePrivate::didRenderContent(const Platform::IntRectRegion& renderedRegion)
{
#if USE(ACCELERATED_COMPOSITING)
if (m_webPage->d->needsOneShotDrawingSynchronization())
m_webPage->d->commitRootLayerIfNeeded();
else
#endif
{
if (isScrollingOrZooming())
return;
blitVisibleContents();
}
if (!m_client->contentsSize().isEmpty()) {
std::vector<Platform::IntRect> renderedRects = renderedRegion.rects();
for (size_t i = 0; i < renderedRects.size(); ++i)
m_webPage->client()->notifyPixelContentRendered(renderedRects[i]);
}
}
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::suspendBackingStoreUpdates()
{
d->suspendBackingStoreUpdates();
}
void BackingStore::resumeBackingStoreUpdates()
{
d->resumeBackingStoreUpdates();
}
void BackingStore::suspendGeometryUpdates()
{
d->suspendGeometryUpdates();
}
void BackingStore::resumeGeometryUpdates()
{
d->resumeGeometryUpdates();
}
void BackingStore::suspendScreenUpdates()
{
d->suspendScreenUpdates();
}
void BackingStore::resumeScreenUpdates(ResumeUpdateOperation op)
{
d->resumeScreenUpdates(op);
}
bool BackingStore::isScrollingOrZooming() const
{
return d->isScrollingOrZooming();
}
void BackingStore::setScrollingOrZooming(bool scrollingOrZooming)
{
d->setScrollingOrZooming(scrollingOrZooming);
}
void BackingStore::blitVisibleContents()
{
d->blitVisibleContents(false );
}
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);
}
void BackingStore::acquireBackingStoreMemory()
{
SurfacePool::globalSurfacePool()->createBuffers();
}
void BackingStore::releaseOwnedBackingStoreMemory()
{
if (BackingStorePrivate::s_currentBackingStoreOwner == d->m_webPage) {
d->resetTiles();
SurfacePool::globalSurfacePool()->releaseBuffers();
}
}
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() ? compositor->context()->buffer() : 0;
#endif
return 0;
}
bool BackingStore::drawContents(Platform::Graphics::Buffer* buffer, const Platform::IntRect& dstRect, double scale, const Platform::FloatPoint& documentScrollPosition)
{
if (!buffer || dstRect.isEmpty())
return false;
d->requestLayoutIfNeeded();
return d->renderContents(buffer, dstRect, scale, documentScrollPosition, BackingStorePrivate::RenderAllLayers);
}
}
}