1 /* 2 * Copyright 2007, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "CachedPrefix.h" 27 #include "CachedFrame.h" 28 #include "CachedNode.h" 29 #if DUMP_NAV_CACHE 30 #include "CachedRoot.h" 31 #endif 32 33 #include "CachedHistory.h" 34 35 namespace android { 36 37 CachedHistory::CachedHistory() { 38 memset(this, 0, sizeof(CachedHistory)); // this assume the class has no virtuals 39 mLastMove = CachedFrame::UNINITIALIZED; 40 mPriorMove = CachedFrame::UNINITIALIZED; 41 } 42 43 44 void CachedHistory::addToVisited(const CachedNode* node, CachedFrame::Direction direction) 45 { 46 memmove(&mVisited[1], &mVisited[0], sizeof(mVisited) - sizeof(mVisited[0])); 47 mVisited[0].mNode = node; 48 mVisited[0].mDirection = direction; 49 } 50 51 bool CachedHistory::checkVisited(const CachedNode* node, CachedFrame::Direction direction) const 52 { 53 // if the direction is unchanged and we've already visited this node, don't visit it again 54 int index = 0; 55 while (index < NAVIGATION_VISIT_DEPTH - 1) { 56 if (direction != mVisited[index].mDirection) 57 break; 58 index++; // compare with last direction, previous to last node (where the arrow took us from) 59 if (node == mVisited[index].mNode) 60 return false; 61 } 62 return true; 63 } 64 65 void CachedHistory::pinMaxMin(const WebCore::IntRect& viewBounds) 66 { 67 if (mMinWorkingHorizontal < viewBounds.y() || 68 mMinWorkingHorizontal >= viewBounds.bottom()) 69 mMinWorkingHorizontal = viewBounds.y(); 70 if (mMaxWorkingHorizontal > viewBounds.bottom() || 71 mMaxWorkingHorizontal <= viewBounds.y()) 72 mMaxWorkingHorizontal = viewBounds.bottom(); 73 if (mMinWorkingVertical < viewBounds.x() || 74 mMinWorkingVertical >= viewBounds.right()) 75 mMinWorkingVertical = viewBounds.x(); 76 if (mMaxWorkingVertical > viewBounds.right() || 77 mMaxWorkingVertical <= viewBounds.x()) 78 mMaxWorkingVertical = viewBounds.right(); 79 } 80 81 void CachedHistory::reset() 82 { 83 memset(mVisited, 0, sizeof(mVisited)); 84 // mLastScroll = 0; 85 mPriorBounds = WebCore::IntRect(0, 0, 0, 0); 86 mDirectionChange = false; 87 mDidFirstLayout = false; 88 mPriorMove = mLastMove = CachedFrame::UNINITIALIZED; 89 mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN; 90 mMaxWorkingHorizontal = mMaxWorkingVertical = INT_MAX; 91 } 92 93 void CachedHistory::setWorking(CachedFrame::Direction newMove, 94 const CachedFrame* cursorFrame, const CachedNode* cursor, 95 const WebCore::IntRect& viewBounds) 96 { 97 CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized 98 CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN); 99 bool change = newAxis != lastAxis; 100 mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED; 101 if (cursor != NULL || mLastMove != CachedFrame::UNINITIALIZED) { 102 mPriorMove = mLastMove; 103 mLastMove = newMove; 104 } 105 const WebCore::IntRect* navBounds = &mNavBounds; 106 if (cursor != NULL) { 107 WebCore::IntRect cursorBounds = cursor->bounds(cursorFrame); 108 if (cursorBounds.isEmpty() == false) 109 mNavBounds = cursorBounds; 110 } 111 if (change) { // uninitialized or change in direction 112 if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) { 113 mMinWorkingHorizontal = navBounds->y(); 114 mMaxWorkingHorizontal = navBounds->bottom(); 115 } 116 if (lastAxis != CachedFrame::UP && navBounds->width() > 0) { 117 mMinWorkingVertical = navBounds->x(); 118 mMaxWorkingVertical = navBounds->right(); 119 } 120 } 121 pinMaxMin(viewBounds); 122 } 123 124 #if DUMP_NAV_CACHE 125 126 #define DEBUG_PRINT_BOOL(field) \ 127 DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") 128 129 #define DEBUG_PRINT_RECT(field) \ 130 { const WebCore::IntRect& r = b->field; \ 131 DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \ 132 r.x(), r.y(), r.width(), r.height()); } 133 134 CachedHistory* CachedHistory::Debug::base() const { 135 CachedHistory* nav = (CachedHistory*) ((char*) this - OFFSETOF(CachedHistory, mDebug)); 136 return nav; 137 } 138 139 const char* CachedHistory::Debug::direction(CachedFrame::Direction d) const 140 { 141 switch (d) { 142 case CachedFrame::LEFT: return "LEFT"; break; 143 case CachedFrame::RIGHT: return "RIGHT"; break; 144 case CachedFrame::UP: return "UP"; break; 145 case CachedFrame::DOWN: return "DOWN"; break; 146 default: return "UNINITIALIZED"; 147 } 148 } 149 150 void CachedHistory::Debug::print(CachedRoot* root) const 151 { 152 CachedHistory* b = base(); 153 DUMP_NAV_LOGD("// Visited mVisited[]={\n"); 154 for (size_t i = 0; i < NAVIGATION_VISIT_DEPTH; i++) { 155 const Visited& visit = b->mVisited[i]; 156 const CachedNode* node = visit.mNode; 157 int index = root != NULL && root->CachedFrame::mDebug.validate(node) ? 158 node->index() : -1; 159 DUMP_NAV_LOGD(" // { 0x%p (%d), %s },\n", node, index, direction(visit.mDirection)); 160 } 161 DUMP_NAV_LOGD("// };\n"); 162 // DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll); 163 DEBUG_PRINT_RECT(mMouseBounds); 164 DEBUG_PRINT_RECT(mNavBounds); 165 DEBUG_PRINT_RECT(mPriorBounds); 166 DEBUG_PRINT_BOOL(mDirectionChange); 167 DEBUG_PRINT_BOOL(mDidFirstLayout); 168 DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n", 169 direction(b->mLastMove), direction(b->mPriorMove)); 170 int max = b->mMaxWorkingHorizontal; 171 DUMP_NAV_LOGD("static int TEST_MAX_H = %d;\n", max); 172 int min = b->mMinWorkingHorizontal; 173 if (min == INT_MIN) 174 min++; 175 DUMP_NAV_LOGD("static int TEST_MIN_H = %d;\n", min); 176 max = b->mMaxWorkingVertical; 177 DUMP_NAV_LOGD("static int TEST_MAX_V = %d;\n", max); 178 min = b->mMinWorkingVertical; 179 if (min == INT_MIN) 180 min++; 181 DUMP_NAV_LOGD("static int TEST_MIN_V = %d;\n", min); 182 DUMP_NAV_LOGD("\n"); 183 } 184 185 #endif 186 187 } 188