Home | History | Annotate | Download | only in android
      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 "android_graphics.h"
     28 #include "CachedRoot.h"
     29 #include "IntRect.h"
     30 #include "LayerAndroid.h"
     31 #include "SkCanvas.h"
     32 #include "SkCornerPathEffect.h"
     33 #include "SkPath.h"
     34 #include "SkRegion.h"
     35 #include "WebViewCore.h"
     36 
     37 namespace android {
     38 
     39 ///////////////////////////////////////////////////////////////////////////////
     40 
     41 const static SkColor cursorOuterColors[] = {
     42     SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal ring select
     43     SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake ring select, for phone, email, text
     44     SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal ring pressed
     45     SkColorSetARGB(0xff, 0x36, 0xc0, 0x00)  // fake ring pressed
     46 };
     47 
     48 const static SkColor cursorInnerColors[] = {
     49     SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal ring select
     50     SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake ring select, for phone, email, text
     51     SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal ring pressed
     52     SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00)  // fake ring pressed
     53 };
     54 
     55 const static SkColor cursorPressedColors[] = {
     56     SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal ring pressed
     57     SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00)  // fake ring pressed
     58 };
     59 
     60 #define CURSOR_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
     61 #define CURSOR_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
     62 #define CURSOR_RING_OUTER_OUTSET 2 // used to inflate rects added to region
     63 
     64 void CursorRing::draw(SkCanvas* canvas, LayerAndroid* layer)
     65 {
     66 #if USE(ACCELERATED_COMPOSITING)
     67     int layerId = m_node->isInLayer() ? m_frame->layer(m_node)->uniqueId() : -1;
     68     if (layer->uniqueId() != layerId)
     69         return;
     70 #endif
     71     if (canvas->quickReject(m_bounds, SkCanvas::kAA_EdgeType)) {
     72         DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)"
     73             " bounds=(%d,%d,w=%d,h=%d)", m_node->index(), m_node->nodePointer(),
     74             m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height());
     75         m_followedLink = false;
     76         return;
     77     }
     78     unsigned rectCount = m_rings.size();
     79     SkRegion rgn;
     80     SkPath path;
     81     for (unsigned i = 0; i < rectCount; i++)
     82     {
     83         SkRect  r(m_rings[i]);
     84         SkIRect ir;
     85 
     86         r.round(&ir);
     87         ir.inset(-CURSOR_RING_OUTER_OUTSET, -CURSOR_RING_OUTER_OUTSET);
     88         rgn.op(ir, SkRegion::kUnion_Op);
     89     }
     90     rgn.getBoundaryPath(&path);
     91 
     92     SkPaint paint;
     93     paint.setAntiAlias(true);
     94     paint.setPathEffect(new SkCornerPathEffect(CURSOR_RING_ROUNDEDNESS))->unref();
     95     if (m_flavor >= NORMAL_ANIMATING) { // pressed
     96         paint.setColor(cursorPressedColors[m_flavor - NORMAL_ANIMATING]);
     97         canvas->drawPath(path, paint);
     98     }
     99     paint.setStyle(SkPaint::kStroke_Style);
    100     paint.setStrokeWidth(CURSOR_RING_OUTER_DIAMETER);
    101     paint.setColor(cursorOuterColors[m_flavor]);
    102     canvas->drawPath(path, paint);
    103     paint.setStrokeWidth(CURSOR_RING_INNER_DIAMETER);
    104     paint.setColor(cursorInnerColors[m_flavor]);
    105     canvas->drawPath(path, paint);
    106 }
    107 
    108 bool CursorRing::setup()
    109 {
    110     m_node->localCursorRings(m_frame, &m_rings);
    111     if (!m_rings.size()) {
    112         DBG_NAV_LOG("!rings.size()");
    113         m_viewImpl->m_hasCursorBounds = false;
    114         return false;
    115     }
    116     m_isButton = false;
    117     m_viewImpl->gButtonMutex.lock();
    118     // If this is a button drawn by us (rather than webkit) do not draw the
    119     // cursor ring, since its cursor will be shown by a change in what we draw.
    120     // Should be in sync with recordButtons, since that will be called
    121     // before this.
    122     if (m_viewImpl->m_buttons.size() > 0) {
    123         WebCore::Node* cursorPointer = (WebCore::Node*) m_node->nodePointer();
    124         Container* end = m_viewImpl->m_buttons.end();
    125         for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
    126             if (ptr->matches(cursorPointer)) {
    127                 m_isButton = true;
    128                 break;
    129             }
    130         }
    131     }
    132     m_viewImpl->gButtonMutex.unlock();
    133     m_bounds = m_node->localBounds(m_frame);
    134     m_viewImpl->updateCursorBounds(m_root, m_frame, m_node);
    135 
    136     bool useHitBounds = m_node->useHitBounds();
    137     if (useHitBounds)
    138         m_bounds = m_node->localHitBounds(m_frame);
    139     if (useHitBounds || m_node->useBounds()) {
    140         m_rings.clear();
    141         m_rings.append(m_bounds);
    142     }
    143     m_bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER));
    144     if (!m_node->hasCursorRing() || (m_node->isPlugin() && m_node->isFocus()))
    145         return false;
    146     m_flavor = NORMAL_FLAVOR;
    147     if (!m_isButton) {
    148         m_flavor = m_node->isSyntheticLink() ? FAKE_FLAVOR : NORMAL_FLAVOR;
    149         if (m_followedLink) {
    150             m_flavor = static_cast<Flavor>(m_flavor + NORMAL_ANIMATING);
    151         }
    152 #if DEBUG_NAV_UI
    153         const WebCore::IntRect& ring = m_rings[0];
    154         DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d"
    155             " (%d, %d, %d, %d) isPlugin=%s",
    156             m_node->index(), m_node->nodePointer(),
    157             m_flavor == FAKE_FLAVOR ? "FAKE_FLAVOR" :
    158             m_flavor == NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
    159             m_flavor == FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR",
    160             m_rings.size(), ring.x(), ring.y(), ring.width(), ring.height(),
    161             m_node->isPlugin() ? "true" : "false");
    162 #endif
    163     }
    164     return true;
    165 }
    166 
    167 }
    168