static QString dumpPath(WebCore::Node *node) { QString str = node->nodeName(); WebCore::Node *parent = node->parentNode(); while (parent) { str.append(QLatin1String(" > ")); str.append(parent->nodeName()); parent = parent->parentNode(); } return str; }
void DocumentNavigator::FindBestNode(WebCore::Node* rootNode) { // Note by Arpit Baldeva - Changed the recursive algorithm to an iterative algorithm. This results in 25% to 40% increase in efficiency. while (rootNode) { IsNodeNavigableDelegate nodeNavigableDelegate(mView); // As it turns out, getRect on HTMLElement is pretty expensive. So we don't do it inside the delegate as we require getRect here too. We do that check here. // It is at least ~15% more efficient and can be up to ~25% more efficient (depends on the page layout and current node you are at). nodeNavigableDelegate(rootNode,false); if (nodeNavigableDelegate.FoundNode()) { WebCore::HTMLElement* htmlElement = (WebCore::HTMLElement*) rootNode; WebCore::IntRect rectAbsolute = htmlElement->getRect(); // Adjust the rectangle position based on the frame offset so that we have absolute geometrical position. WebCore::FrameView* pFrameView = htmlElement->document()->view(); //Can be NULL if(pFrameView) { rectAbsolute.setX(rectAbsolute.x() + pFrameView->x()); rectAbsolute.setY(rectAbsolute.y() + pFrameView->y()); } /* printf("Looking at ELEMENT_NODE : nodeName=%S (%d,%d)->(%d,%d) ThetaRange(%f,%f)\n\n%S\n-----------------------------------\n", htmlElement->tagName().charactersWithNullTermination(), rect.topLeft().x(),rect.topLeft().y(), rect.bottomRight().x(), rect.bottomRight().y(), mMinThetaRange,mMaxThetaRange, htmlElement->innerHTML().charactersWithNullTermination() ); */ if (!WouldBeTrappedInElement(rectAbsolute,mStartingPosition,mDirection)) { if (!TryingToDoPerpendicularJump(rectAbsolute,mPreviousNodeRect,mDirection)) { if(rectAbsolute.width()>=1 && rectAbsolute.height() >= 1) //Avoid 0 size elements { if (doAxisCheck(rectAbsolute)) { PolarRegion pr(rectAbsolute, mStartingPosition); if (pr.minR < mMinR ) { if (areAnglesInRange(pr.minTheta,pr.maxTheta)) { mMinR = pr.minR; EAW_ASSERT( *(uint32_t*)rootNode > 10000000u ); //mBestNode = rootNode; //We don't assign it here since we do the Z-layer testing later on. FoundNodeInfo foundNodeInfo = {rootNode, mMinR}; mNodeListContainer->mFoundNodes.push_back(foundNodeInfo); /*printf("Found ELEMENT_NODE : nodeName=%s (%d,%d)->(%d,%d) polar: R(%f,%f) Theta(%f,%f) ThetaRange(%f,%f) \n", (char*)htmlElement->nodeName().characters(), rect.topLeft().x(),rect.topLeft().y(), rect.bottomRight().x(), rect.bottomRight().y(), pr.minR,pr.maxR,pr.minTheta,pr.maxTheta, mMinThetaRange,mMaxThetaRange );*/ } else { #if EAWEBKIT_ENABLE_JUMP_NAVIGATION_DEBUGGING mNodeListContainer->mRejectedByAngleNodes.push_back(rootNode); #endif /*printf("RejectedA ELEMENT_NODE : nodeName=%s (%d,%d)->(%d,%d) polar: R(%f,%f) Theta(%f,%f) ThetaRange(%f,%f) \n", (char*)htmlElement->nodeName().characters(), rect.topLeft().x(),rect.topLeft().y(), rect.bottomRight().x(), rect.bottomRight().y(), pr.minR,pr.maxR,pr.minTheta,pr.maxTheta, mMinThetaRange,mMaxThetaRange );*/ } } else { #if EAWEBKIT_ENABLE_JUMP_NAVIGATION_DEBUGGING mNodeListContainer->mRejectedByRadiusNodes.push_back(rootNode); #endif /*printf("RejectedR ELEMENT_NODE : nodeName=%s (%d,%d)->(%d,%d) polar: R(%f,%f) Theta(%f,%f) ThetaRange(%f,%f) \n", (char*)htmlElement->nodeName().characters(), rect.topLeft().x(),rect.topLeft().y(), rect.bottomRight().x(), rect.bottomRight().y(), pr.minR,pr.maxR,pr.minTheta,pr.maxTheta, mMinThetaRange,mMaxThetaRange );*/ } } else { //printf(" - failed axis check\n"); } } else { //printf(" - too small\n"); } } else { //printf(" - perpendicular\n"); } } else { #if EAWEBKIT_ENABLE_JUMP_NAVIGATION_DEBUGGING mNodeListContainer->mRejectedWouldBeTrappedNodes.push_back(rootNode); #endif } } rootNode = rootNode->traverseNextNode(); } // Make sure that this element can be jumped to by passing z-check. This makes sure that we jump only on the element // at the top most layer (For example, a CSS+JavaScript pop up). // We don't try and check against Z-layer in the loop above as it has significant performance penalty. On an average, it causes traversal to be 50% slower. So what we do // instead is to collect all the nodes and at the end, traverse this list from the end to begining. It is important to traverse from end as that is where the most suited element is // based on the position. WebCore::Node* bestNode = NULL; float radialDistance = FLT_MAX; // A high value so that the max distance between any two elements in the surface is under it. bool matched = false; for (WebCoreFoundNodeInfoListReverseIterator rIt = mNodeListContainer->mFoundNodes.rbegin(); rIt != mNodeListContainer->mFoundNodes.rend(); ++rIt) { bestNode = (*rIt).mFoundNode; radialDistance = (*rIt).mRadialDistance; WebCore::HTMLElement* element = (WebCore::HTMLElement*)bestNode; WebCore::Frame* frame = element->document()->frame(); WebCore::FrameView* pFrameView = element->document()->view(); WebCore::IntRect rect = element->getRect(); //This list is decently small so we don't worry about caching the rect size. // ElementFromPoint expects the point in its own coordinate system so we don't need to adjust the rectangle to its absolute position // on screen // elementFromPoint API changed compared to 1.x. The simplest thing to do at the moment is to adjust our input. int inputX = (rect.x()+rect.width()/2 - pFrameView->scrollX())/frame->pageZoomFactor(); int inputY = (rect.y()+rect.height()/2 - pFrameView->scrollY())/frame->pageZoomFactor(); WebCore::Node* hitElement = mDocument->elementFromPoint(inputX,inputY); while (hitElement) { if(bestNode == hitElement) { matched = true; break; } hitElement = hitElement->parentNode();//We need to find the element that responds to the events as that is what we jump to. For example, we don't jump to a "span". }; if(matched) break; } if(matched) { mBestNode = bestNode; mMinR = radialDistance; } else { mBestNode = 0; //We didn't match anything based on the Z-layer testing. mMinR = FLT_MAX; } // A way to do Post Order traversal. //while (WebCore::Node* firstChild = rootNode->firstChild()) // rootNode = firstChild; //while(rootNode) //{ // rootNode = rootNode->traverseNextNodePostOrder(); //} /* ////////////////////////////////////////////////////////////////////////// // THEN, FIND THE CHILDREN if (rootNode && rootNode->childNodeCount() > 0) { PassRefPtr<WebCore::NodeList> children = rootNode->childNodes(); const uint32_t length = children->length(); for (uint32_t i=0; i < length; ++i) { WebCore::Node* child = children->item(i); if (child) { FindBestNode(child); } } } */ }