blob: f75f237f6e5b0afb2c46ef69b73ffcf50efe68f4 [file] [log] [blame]
/*
* Copyright 2007, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "CachedPrefix.h"
#include "CachedFrame.h"
#include "CachedNode.h"
#if DUMP_NAV_CACHE
#include "CachedRoot.h"
#endif
#include "CachedHistory.h"
namespace android {
CachedHistory::CachedHistory() {
memset(this, 0, sizeof(CachedHistory)); // this assume the class has no virtuals
mLastMove = CachedFrame::UNINITIALIZED;
mPriorMove = CachedFrame::UNINITIALIZED;
}
void CachedHistory::addToVisited(const CachedNode* node, CachedFrame::Direction direction)
{
memmove(&mVisited[1], &mVisited[0], sizeof(mVisited) - sizeof(mVisited[0]));
mVisited[0].mNode = node;
mVisited[0].mDirection = direction;
}
bool CachedHistory::checkVisited(const CachedNode* node, CachedFrame::Direction direction) const
{
// if the direction is unchanged and we've already visited this node, don't visit it again
int index = 0;
while (index < NAVIGATION_VISIT_DEPTH - 1) {
if (direction != mVisited[index].mDirection)
break;
index++; // compare with last direction, previous to last node (where the arrow took us from)
if (node == mVisited[index].mNode)
return false;
}
return true;
}
void CachedHistory::pinMaxMin(const WebCore::IntRect& viewBounds)
{
if (mMinWorkingHorizontal < viewBounds.y() ||
mMinWorkingHorizontal >= viewBounds.bottom())
mMinWorkingHorizontal = viewBounds.y();
if (mMaxWorkingHorizontal > viewBounds.bottom() ||
mMaxWorkingHorizontal <= viewBounds.y())
mMaxWorkingHorizontal = viewBounds.bottom();
if (mMinWorkingVertical < viewBounds.x() ||
mMinWorkingVertical >= viewBounds.right())
mMinWorkingVertical = viewBounds.x();
if (mMaxWorkingVertical > viewBounds.right() ||
mMaxWorkingVertical <= viewBounds.x())
mMaxWorkingVertical = viewBounds.right();
}
void CachedHistory::reset()
{
memset(mVisited, 0, sizeof(mVisited));
// mLastScroll = 0;
mPriorBounds = WebCore::IntRect(0, 0, 0, 0);
mDirectionChange = false;
mFocusIsInput = false;
mPriorIsInput = false;
mDidFirstLayout = false;
mPriorMove = mLastMove = CachedFrame::UNINITIALIZED;
mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN;
mMaxWorkingHorizontal = mMaxWorkingVertical = INT_MAX;
}
void CachedHistory::setWorking(CachedFrame::Direction newMove,
const CachedNode* focus, const WebCore::IntRect& viewBounds)
{
CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized
CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN);
bool change = newAxis != lastAxis;
mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED;
if (focus != NULL || mLastMove != CachedFrame::UNINITIALIZED) {
mPriorMove = mLastMove;
mLastMove = newMove;
}
const WebCore::IntRect* navBounds = &mNavBounds;
if (focus != NULL) {
WebCore::IntRect focusBounds;
focus->getBounds(&focusBounds);
if (focusBounds.isEmpty() == false)
mNavBounds = focusBounds;
mPriorIsInput = mFocusIsInput;
mFocusIsInput = focus->isInput(); // focus->localName() == "input";
}
if (change) { // uninitialized or change in direction
if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) {
mMinWorkingHorizontal = navBounds->y();
mMaxWorkingHorizontal = navBounds->bottom();
}
if (lastAxis != CachedFrame::UP && navBounds->width() > 0) {
mMinWorkingVertical = navBounds->x();
mMaxWorkingVertical = navBounds->right();
}
} else if (mPriorIsInput) {
if (newAxis == CachedFrame::UP_DOWN) {
if (mPriorBounds.x() == mMinWorkingVertical && mPriorBounds.right() == mMaxWorkingVertical) {
mMinWorkingVertical = navBounds->x();
mMaxWorkingVertical = navBounds->right();
}
} else {
if (mPriorBounds.y() == mMinWorkingHorizontal && mPriorBounds.bottom() == mMaxWorkingHorizontal) {
mMinWorkingHorizontal = navBounds->y();
mMaxWorkingHorizontal = navBounds->bottom();
}
}
}
pinMaxMin(viewBounds);
}
#if DUMP_NAV_CACHE
#define DEBUG_PRINT_BOOL(field) \
DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
#define DEBUG_PRINT_RECT(field) \
{ const WebCore::IntRect& r = b->field; \
DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
r.x(), r.y(), r.width(), r.height()); }
CachedHistory* CachedHistory::Debug::base() const {
CachedHistory* nav = (CachedHistory*) ((char*) this - OFFSETOF(CachedHistory, mDebug));
return nav;
}
const char* CachedHistory::Debug::direction(CachedFrame::Direction d) const
{
switch (d) {
case CachedFrame::LEFT: return "LEFT"; break;
case CachedFrame::RIGHT: return "RIGHT"; break;
case CachedFrame::UP: return "UP"; break;
case CachedFrame::DOWN: return "DOWN"; break;
default: return "UNINITIALIZED";
}
}
void CachedHistory::Debug::print(CachedRoot* root) const
{
CachedHistory* b = base();
DUMP_NAV_LOGD("// Visited mVisited[]={\n");
for (size_t i = 0; i < NAVIGATION_VISIT_DEPTH; i++) {
const Visited& visit = b->mVisited[i];
const CachedNode* node = visit.mNode;
int index = root != NULL && root->CachedFrame::mDebug.validate(node) ?
node->index() : -1;
DUMP_NAV_LOGD(" // { 0x%p (%d), %s },\n", node, index, direction(visit.mDirection));
}
DUMP_NAV_LOGD("// };\n");
// DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll);
DEBUG_PRINT_RECT(mNavBounds);
DEBUG_PRINT_RECT(mPriorBounds);
DEBUG_PRINT_BOOL(mDirectionChange);
DEBUG_PRINT_BOOL(mFocusIsInput);
DEBUG_PRINT_BOOL(mPriorIsInput);
DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n",
direction(b->mLastMove), direction(b->mPriorMove));
int max = b->mMaxWorkingHorizontal;
DUMP_NAV_LOGD("static int TEST_MAX_H = %d;\n", max);
int min = b->mMinWorkingHorizontal;
if (min == INT_MIN)
min++;
DUMP_NAV_LOGD("static int TEST_MIN_H = %d;\n", min);
max = b->mMaxWorkingVertical;
DUMP_NAV_LOGD("static int TEST_MAX_V = %d;\n", max);
min = b->mMinWorkingVertical;
if (min == INT_MIN)
min++;
DUMP_NAV_LOGD("static int TEST_MIN_V = %d;\n", min);
DUMP_NAV_LOGD("\n");
}
#endif
}