bool CursorRing::setup() { m_node->localCursorRings(m_frame, &m_rings); if (!m_rings.size()) { DBG_NAV_LOG("!rings.size()"); m_viewImpl->m_hasCursorBounds = false; return false; } m_isButton = false; m_viewImpl->gButtonMutex.lock(); // If this is a button drawn by us (rather than webkit) do not draw the // cursor ring, since its cursor will be shown by a change in what we draw. // Should be in sync with recordButtons, since that will be called // before this. if (m_viewImpl->m_buttons.size() > 0) { WebCore::Node* cursorPointer = (WebCore::Node*) m_node->nodePointer(); Container* end = m_viewImpl->m_buttons.end(); for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) { if (ptr->matches(cursorPointer)) { m_isButton = true; break; } } } m_viewImpl->gButtonMutex.unlock(); m_bounds = m_node->localBounds(m_frame); m_viewImpl->updateCursorBounds(m_root, m_frame, m_node); bool useHitBounds = m_node->useHitBounds(); if (useHitBounds) m_bounds = m_node->localHitBounds(m_frame); if (useHitBounds || m_node->useBounds()) { m_rings.clear(); m_rings.append(m_bounds); } m_bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER)); if (!m_node->hasCursorRing() || (m_node->isPlugin() && m_node->isFocus())) return false; m_flavor = NORMAL_FLAVOR; if (!m_isButton) { m_flavor = m_node->isSyntheticLink() ? FAKE_FLAVOR : NORMAL_FLAVOR; if (m_followedLink) { m_flavor = static_cast<Flavor>(m_flavor + NORMAL_ANIMATING); } #if DEBUG_NAV_UI const WebCore::IntRect& ring = m_rings[0]; DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d" " (%d, %d, %d, %d) isPlugin=%s", m_node->index(), m_node->nodePointer(), m_flavor == FAKE_FLAVOR ? "FAKE_FLAVOR" : m_flavor == NORMAL_ANIMATING ? "NORMAL_ANIMATING" : m_flavor == FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR", m_rings.size(), ring.x(), ring.y(), ring.width(), ring.height(), m_node->isPlugin() ? "true" : "false"); #endif } return true; }
void doRect() { /* Record the outer bounds of the lines of text that intersect the touch coordinates, given some slop */ if (SkIRect::Intersects(mPartial, mHit)) { if (mHitLeft > mPartial.fLeft) mHitLeft = mPartial.fLeft; DBG_NAV_LOGD("LeftCheck mHitLeft=%d", mHitLeft); } else if (mHitLeft == INT_MAX) return; // wait for intersect success /* If text is too far away vertically, don't consider it */ if (!mBounds.isEmpty() && (mPartial.fTop > mBounds.fBottom + SLOP || mPartial.fBottom < mBounds.fTop - SLOP)) { DBG_NAV_LOGD("LeftCheck stop mPartial=(%d, %d, %d, %d)" " mBounds=(%d, %d, %d, %d)", mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom, mBounds.fLeft, mBounds.fTop, mBounds.fRight, mBounds.fBottom); mHitLeft = INT_MAX; // and disable future comparisons return; } /* If the considered text is completely to the left or right of the touch coordinates, skip it, turn off further detection */ if (mPartial.fLeft > mX || mPartial.fRight < mX) { DBG_NAV_LOGD("LeftCheck stop mX=%d mPartial=(%d, %d, %d, %d)", mX, mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom); mHitLeft = INT_MAX; return; } /* record the smallest margins on the left and right */ if (mMostLeft > mPartial.fLeft) { DBG_NAV_LOGD("LeftCheck new mMostLeft=%d (old=%d)", mPartial.fLeft, mMostLeft); mMostLeft = mPartial.fLeft; } if (mBounds.isEmpty()) mBounds = mPartial; else if (mPartial.fBottom > mBounds.fBottom) { DBG_NAV_LOGD("LeftCheck new bottom=%d (old=%d)", mPartial.fBottom, mBounds.fBottom); mBounds.fBottom = mPartial.fBottom; } }
void CursorRing::draw(SkCanvas* canvas, LayerAndroid* layer) { #if USE(ACCELERATED_COMPOSITING) int layerId = m_node->isInLayer() ? m_frame->layer(m_node)->uniqueId() : -1; if (layer->uniqueId() != layerId) return; #endif if (canvas->quickReject(m_bounds, SkCanvas::kAA_EdgeType)) { DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)" " bounds=(%d,%d,w=%d,h=%d)", m_node->index(), m_node->nodePointer(), m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height()); m_followedLink = false; return; } unsigned rectCount = m_rings.size(); SkRegion rgn; SkPath path; for (unsigned i = 0; i < rectCount; i++) { SkRect r(m_rings[i]); SkIRect ir; r.round(&ir); ir.inset(-CURSOR_RING_OUTER_OUTSET, -CURSOR_RING_OUTER_OUTSET); rgn.op(ir, SkRegion::kUnion_Op); } rgn.getBoundaryPath(&path); SkPaint paint; paint.setAntiAlias(true); paint.setPathEffect(new SkCornerPathEffect(CURSOR_RING_ROUNDEDNESS))->unref(); if (m_flavor >= NORMAL_ANIMATING) { // pressed paint.setColor(cursorPressedColors[m_flavor - NORMAL_ANIMATING]); canvas->drawPath(path, paint); } paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(CURSOR_RING_OUTER_DIAMETER); paint.setColor(cursorOuterColors[m_flavor]); canvas->drawPath(path, paint); paint.setStrokeWidth(CURSOR_RING_INNER_DIAMETER); paint.setColor(cursorInnerColors[m_flavor]); canvas->drawPath(path, paint); }
void CachedNode::fixUpCursorRects(const CachedFrame* frame) { if (mFixedUpCursorRects) return; mFixedUpCursorRects = true; // if the hit-test rect doesn't intersect any other rect, use it if (mHitBounds != mBounds && mHitBounds.contains(mBounds) && frame->checkRings(this, mCursorRing, mHitBounds)) { DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(), mHitBounds.y(), mHitBounds.width(), mHitBounds.height()); mUseHitBounds = true; return; } if (mNavableRects <= 1) return; // if there is more than 1 rect, and the bounds doesn't intersect // any other cursor ring bounds, use it if (frame->checkRings(this, mCursorRing, mBounds)) { DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(), mBounds.y(), mBounds.width(), mBounds.height()); mUseBounds = true; return; } #if DEBUG_NAV_UI { WebCore::IntRect* boundsPtr = mCursorRing.begin() - 1; const WebCore::IntRect* const boundsEnd = mCursorRing.begin() + mCursorRing.size(); while (++boundsPtr < boundsEnd) LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, boundsPtr - mCursorRing.begin(), boundsPtr->x(), boundsPtr->y(), boundsPtr->width(), boundsPtr->height()); } #endif // q: need to know when rects are for drawing and hit-testing, but not mouse down calcs? bool again; do { again = false; size_t size = mCursorRing.size(); WebCore::IntRect* unitBoundsPtr = mCursorRing.begin() - 1; const WebCore::IntRect* const unitBoundsEnd = mCursorRing.begin() + size; while (++unitBoundsPtr < unitBoundsEnd) { // any other unitBounds to the left or right of this one? int unitTop = unitBoundsPtr->y(); int unitBottom = unitBoundsPtr->bottom(); int unitLeft = unitBoundsPtr->x(); int unitRight = unitBoundsPtr->right(); WebCore::IntRect* testBoundsPtr = mCursorRing.begin() - 1; while (++testBoundsPtr < unitBoundsEnd) { if (unitBoundsPtr == testBoundsPtr) continue; int testTop = testBoundsPtr->y(); int testBottom = testBoundsPtr->bottom(); int testLeft = testBoundsPtr->x(); int testRight = testBoundsPtr->right(); int candidateTop = unitTop > testTop ? unitTop : testTop; int candidateBottom = unitBottom < testBottom ? unitBottom : testBottom; int candidateLeft = unitRight < testLeft ? unitRight : testRight; int candidateRight = unitRight > testLeft ? unitLeft : testLeft; bool leftRight = true; if (candidateTop + OVERLAP >= candidateBottom || candidateLeft + OVERLAP >= candidateRight) { candidateTop = unitBottom < testTop ? unitBottom : testBottom; candidateBottom = unitBottom > testTop ? unitTop : testTop; candidateLeft = unitLeft > testLeft ? unitLeft : testLeft; candidateRight = unitRight < testRight ? unitRight : testRight; if (candidateTop + OVERLAP >= candidateBottom || candidateLeft + OVERLAP >= candidateRight) continue; leftRight = false; } // construct candidate to add WebCore::IntRect candidate = WebCore::IntRect(candidateLeft, candidateTop, candidateRight - candidateLeft, candidateBottom - candidateTop); // does a different unit bounds intersect the candidate? if so, don't add WebCore::IntRect* checkBoundsPtr = mCursorRing.begin() - 1; while (++checkBoundsPtr < unitBoundsEnd) { if (checkBoundsPtr->intersects(candidate) == false) continue; if (leftRight) { if (candidateTop >= checkBoundsPtr->y() && candidateBottom > checkBoundsPtr->bottom()) candidateTop = checkBoundsPtr->bottom(); else if (candidateTop < checkBoundsPtr->y() && candidateBottom <= checkBoundsPtr->bottom()) candidateBottom = checkBoundsPtr->y(); else goto nextCheck; } else { if (candidateLeft >= checkBoundsPtr->x() && candidateRight > checkBoundsPtr->right()) candidateLeft = checkBoundsPtr->right(); else if (candidateLeft < checkBoundsPtr->x() && candidateRight <= checkBoundsPtr->right()) candidateRight = checkBoundsPtr->x(); else goto nextCheck; } } candidate = WebCore::IntRect(candidateLeft, candidateTop, candidateRight - candidateLeft, candidateBottom - candidateTop); ASSERT(candidate.isEmpty() == false); #if DEBUG_NAV_UI LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, mCursorRing.size(), candidate.x(), candidate.y(), candidate.width(), candidate.height()); #endif mCursorRing.append(candidate); again = true; goto tryAgain; nextCheck: continue; } } tryAgain: ; } while (again); }