1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
|
/*
* Copyright (C) 2012, 2013 Research In Motion Limited. All rights reserved.
*/
#include "config.h"
#include "ProximityDetector.h"
#include "Document.h"
#include "Element.h"
#include "ExceptionCode.h"
#include "HTMLNames.h"
#include "HitTestResult.h"
#include "RenderLayer.h"
#include "RenderObject.h"
#include "RenderView.h"
#include "WebPage_p.h"
using namespace WebCore;
namespace BlackBerry {
namespace WebKit {
static int getPriorityLevel(Node* node)
{
// Priority level is ascending with zero being the lowest.
if (node->isTextNode())
return 1;
if (!node->isElementNode())
return 0;
Element* element = toElement(node);
ASSERT(element);
ExceptionCode ec = 0;
if (element->webkitMatchesSelector("img,obj", ec))
return 1;
if (element->hasTagName(HTMLNames::pTag))
return 2;
if (element->webkitMatchesSelector("h1,h2,h3,h4,h5,h6", ec))
return 3;
return 0;
}
ProximityDetector::ProximityDetector(WebPagePrivate* webPage)
: m_webPage(webPage)
{
}
ProximityDetector::~ProximityDetector()
{
}
IntPoint ProximityDetector::findBestPoint(const IntPoint& documentPos, const IntRect& documentPaddingRect)
{
ASSERT(m_webPage);
if (!m_webPage->m_mainFrame)
return documentPos;
Document* document = m_webPage->m_mainFrame->document();
if (!document || !document->frame()->view())
return documentPos;
unsigned left = -documentPaddingRect.x();
unsigned top = -documentPaddingRect.y();
unsigned right = documentPaddingRect.maxX();
unsigned bottom = documentPaddingRect.maxY();
// Adjust hit point to frame
IntPoint frameContentPos(document->frame()->view()->windowToContents(m_webPage->m_mainFrame->view()->contentsToWindow(documentPos)));
HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
HitTestResult result(frameContentPos, top, right, bottom, left);
document->renderView()->layer()->hitTest(request, result);
IntPoint bestPoint = documentPos;
int bestPriority = 0;
// Iterate over the list of nodes checking both priority and location
ListHashSet<RefPtr<Node> > intersectedNodes = result.rectBasedTestResult();
ListHashSet<RefPtr<Node> >::const_iterator it = intersectedNodes.begin();
ListHashSet<RefPtr<Node> >::const_iterator end = intersectedNodes.end();
for ( ; it != end; ++it) {
Node* curNode = (*it).get();
if (!curNode || !curNode->renderer())
continue;
IntRect curRect = curNode->renderer()->absoluteBoundingBoxRect(true /*use transforms*/);
IntRect hitTestRect = HitTestLocation::rectForPoint(documentPos, top, right, bottom, left);
// Check that top corner does not exceed padding
if (!hitTestRect.contains(curRect.location()))
continue;
int priority = getPriorityLevel(curNode);
if (!priority)
continue;
bool equalPriorityAndCloser = (priority == bestPriority) && (documentPos.distanceSquaredToPoint(bestPoint) > documentPos.distanceSquaredToPoint(curRect.location()));
if (priority > bestPriority || equalPriorityAndCloser) {
bestPoint = curRect.location(); // use top left
bestPriority = priority;
}
}
return bestPoint;
}
}
}
|