/* * 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. */ #ifndef CachedFrame_H #define CachedFrame_H #include "CachedNode.h" #include "IntRect.h" #include "SkFixed.h" #include "wtf/Vector.h" namespace WebCore { class Frame; class Node; } namespace android { class CachedHistory; class CachedRoot; // first node referenced by cache is always document class CachedFrame { public: enum Direction { UNINITIALIZED = -1, LEFT, RIGHT, UP, DOWN, DIRECTION_COUNT, DIRECTION_MASK = DIRECTION_COUNT - 1, UP_DOWN = UP & DOWN, // mask and result RIGHT_DOWN = RIGHT & DOWN, // mask and result }; enum Compare { UNDECIDED = -1, TEST_IS_BEST, REJECT_TEST }; CachedFrame() {} void add(CachedNode& node) { mCachedNodes.append(node); } void addFrame(CachedFrame& child) { mCachedFrames.append(child); } bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; size_t childCount() { return mCachedFrames.size(); } void clearFocus(); const CachedNode* currentFocus() const { return currentFocus(NULL); } const CachedNode* currentFocus(const CachedFrame** ) const; bool directionChange() const; const CachedNode* document() const { return mCachedNodes.begin(); } bool empty() const { return mCachedNodes.size() < 2; } // must have 1 past doc const CachedNode* findBestAt(const WebCore::IntRect& , int* best, const CachedNode** , const CachedFrame** , int* x, int* y) const; const CachedFrame* findBestFrameAt(int x, int y) const; const CachedNode* findBestHitAt(const WebCore::IntRect& , int* best, const CachedFrame** , int* x, int* y) const; bool finishInit(); CachedFrame* firstChild() { return mCachedFrames.begin(); } const CachedFrame* firstChild() const { return mCachedFrames.begin(); } int focusIndex() const { return mFocus; } void* framePointer() const { return mFrame; } CachedNode* getIndex(int index) { return index >= 0 ? &mCachedNodes[index] : NULL; } const CachedFrame* hasFrame(const CachedNode* node) const; int indexInParent() const { return mIndex; } void init(const CachedRoot* root, int index, WebCore::Frame* frame); const CachedFrame* lastChild() const { return &mCachedFrames.last(); } CachedNode* lastNode() { return &mCachedNodes.last(); } CachedFrame* lastChild() { return &mCachedFrames.last(); } const CachedFrame* parent() const { return mParent; } CachedFrame* parent() { return mParent; } bool sameFrame(const CachedFrame* ) const; void removeLast() { mCachedNodes.removeLast(); } void resetClippedOut(); void setContentsSize(int width, int height) { mContents.setWidth(width); mContents.setHeight(height); } void setData(); bool setFocus(WebCore::Frame* , WebCore::Node* , int x, int y); void setFocusIndex(int focusIndex) const { mFocus = focusIndex; } void setLocalViewBounds(const WebCore::IntRect& bounds) { mLocalViewBounds = bounds; } int size() { return mCachedNodes.size(); } const CachedNode* validDocument() const; protected: struct BestData { WebCore::IntRect mNodeBounds; WebCore::IntRect mMouseBounds; int mDistance; int mSideDistance; int mMajorDelta; // difference of center of object // used only when leading and trailing edges contain another set of edges int mMajorDelta2; // difference of leading edge (only used when center is same) int mMajorButt; // checks for next cell butting up against or close to previous one int mWorkingDelta; int mWorkingDelta2; int mNavDelta; int mNavDelta2; const CachedFrame* mFrame; const CachedNode* mNode; SkFixed mWorkingOverlap; // this and below are fuzzy answers instead of bools SkFixed mNavOverlap; SkFixed mPreferred; bool mFocusChild; bool mInNav; bool mNavOutside; bool mWorkingOutside; int bottom() const { return bounds().bottom(); } const WebCore::IntRect& bounds() const { return mNodeBounds; } bool canBeReachedByAnotherDirection(); int height() const { return bounds().height(); } bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; } bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; } int isContainer(BestData* ); static SkFixed Overlap(int span, int left, int right); void reset() { mNode = NULL; } int right() const { return bounds().right(); } void setDistances(); bool setDownDirection(const CachedHistory* ); bool setLeftDirection(const CachedHistory* ); bool setRightDirection(const CachedHistory* ); bool setUpDirection(const CachedHistory* ); void setNavInclusion(int left, int right); void setNavOverlap(int span, int left, int right); void setWorkingInclusion(int left, int right); void setWorkingOverlap(int span, int left, int right); int width() const { return bounds().width(); } int x() const { return bounds().x(); } int y() const { return bounds().y(); } }; typedef const CachedNode* (CachedFrame::*MoveInDirection)( const CachedNode* test, const CachedNode* limit, BestData* bestData, const CachedNode* focus) const; void adjustToTextColumn(int* delta) const; static bool CheckBetween(Direction , const WebCore::IntRect& bestRect, const WebCore::IntRect& prior, WebCore::IntRect* result); bool checkBetween(BestData* , Direction ); int compare(BestData& testData, const BestData& bestData, const CachedNode* focus) const; void findClosest(BestData* , Direction original, Direction test, WebCore::IntRect* clip) const; int frameNodeCommon(BestData& testData, const CachedNode* test, BestData* bestData, BestData* originalData, const CachedNode* focus) const; int framePartCommon(BestData& testData, const CachedNode* test, BestData* bestData, const CachedNode* focus) const; const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit, BestData* , const CachedNode* focus) const; const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit, BestData* , const CachedNode* focus) const; const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit, BestData* , const CachedNode* focus) const; const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit, BestData* , const CachedNode* focus) const; int minWorkingHorizontal() const; int minWorkingVertical() const; int maxWorkingHorizontal() const; int maxWorkingVertical() const; bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* best, const CachedNode* focus) const; const WebCore::IntRect& _navBounds() const; WebCore::IntRect mContents; WebCore::IntRect mLocalViewBounds; WebCore::IntRect mViewBounds; WTF::Vector mCachedNodes; WTF::Vector mCachedFrames; void* mFrame; // WebCore::Frame*, used only to compare pointers CachedFrame* mParent; int mIndex; // index within parent's array of children, or -1 if root const CachedRoot* mRoot; mutable int mFocus; private: CachedHistory* history() const; #ifdef BROWSER_DEBUG public: CachedNode* find(WebCore::Node* ); // !!! probably debugging only int mDebugIndex; int mDebugLoopbackOffset; #endif #if !defined NDEBUG || DUMP_NAV_CACHE public: class Debug { public: Debug() { #if DUMP_NAV_CACHE mFrameName[0] = '\0'; #endif #if !defined NDEBUG mInUse = true; #endif } #if !defined NDEBUG ~Debug() { mInUse = false; } bool mInUse; #endif #if DUMP_NAV_CACHE CachedFrame* base() const; void print() const; bool validate(const CachedNode* ) const; char mFrameName[256]; #endif } mDebug; #endif }; } #endif