• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "CachedColor.h"
29 #include "CachedRoot.h"
30 #include "IntRect.h"
31 #include "LayerAndroid.h"
32 #include "SkCanvas.h"
33 #include "SkCornerPathEffect.h"
34 #include "SkPath.h"
35 #include "SkRegion.h"
36 #include "WebViewCore.h"
37 
38 namespace android {
39 
40 // The CSS values for the inner and outer widths may be specified as fractions
41 #define WIDTH_SCALE 0.0625f // 1/16, to offset the scale in CSSStyleSelector
42 
draw(SkCanvas * canvas,LayerAndroid * layer,IntRect * inval)43 void CursorRing::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
44 {
45     if (!m_lastBounds.isEmpty()) {
46         *inval = m_lastBounds;
47         m_lastBounds = IntRect(0, 0, 0, 0);
48     }
49 #if USE(ACCELERATED_COMPOSITING)
50     int layerId = m_node->isInLayer() ? m_frame->layer(m_node)->uniqueId() : -1;
51     if (layer->uniqueId() != layerId)
52         return;
53 #endif
54     if (canvas->quickReject(m_bounds, SkCanvas::kAA_EdgeType)) {
55         DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)"
56             " bounds=(%d,%d,w=%d,h=%d)", m_node->index(), m_node->nodePointer(),
57             m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height());
58         return;
59     }
60     const CachedColor& colors = m_frame->color(m_node);
61     unsigned rectCount = m_rings.size();
62     SkRegion rgn;
63     SkPath path;
64     for (unsigned i = 0; i < rectCount; i++)
65     {
66         SkRect  r(m_rings[i]);
67         SkIRect ir;
68 
69         r.round(&ir);
70         ir.inset(-colors.outset(), -colors.outset());
71         rgn.op(ir, SkRegion::kUnion_Op);
72     }
73     rgn.getBoundaryPath(&path);
74 
75     SkPaint paint;
76     paint.setAntiAlias(true);
77     paint.setPathEffect(new SkCornerPathEffect(
78         SkIntToScalar(colors.radius())))->unref();
79     SkColor outer;
80     SkColor inner;
81     if (m_isPressed) {
82         SkColor pressed;
83         pressed = colors.fillColor();
84         paint.setColor(pressed);
85         canvas->drawPath(path, paint);
86         outer = colors.pressedOuterColor();
87         inner = colors.pressedInnerColor();
88     } else {
89         outer = colors.selectedOuterColor();
90         inner = colors.selectedInnerColor();
91     }
92     paint.setStyle(SkPaint::kStroke_Style);
93     paint.setStrokeWidth(colors.outerWidth() * WIDTH_SCALE);
94     paint.setColor(outer);
95     canvas->drawPath(path, paint);
96     paint.setStrokeWidth(colors.innerWidth() * WIDTH_SCALE);
97     paint.setColor(inner);
98     canvas->drawPath(path, paint);
99     SkRect localBounds, globalBounds;
100     localBounds = path.getBounds();
101     float width = std::max(colors.innerWidth(), colors.outerWidth());
102     width *= WIDTH_SCALE;
103     localBounds.inset(-width, -width);
104     const SkMatrix& matrix = canvas->getTotalMatrix();
105     matrix.mapRect(&globalBounds, localBounds);
106     SkIRect globalIBounds;
107     globalBounds.round(&globalIBounds);
108     m_lastBounds = globalIBounds;
109     inval->unite(m_lastBounds);
110 }
111 
setIsButton(const CachedNode * node)112 void CursorRing::setIsButton(const CachedNode* node)
113 {
114     m_isButton = false;
115     m_viewImpl->gButtonMutex.lock();
116     // If this is a button drawn by us (rather than webkit) do not draw the
117     // cursor ring, since its cursor will be shown by a change in what we draw.
118     // Should be in sync with recordButtons, since that will be called
119     // before this.
120     if (m_viewImpl->m_buttons.size() > 0) {
121         WebCore::Node* cursorPointer = (WebCore::Node*) node->nodePointer();
122         Container* end = m_viewImpl->m_buttons.end();
123         for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
124             if (ptr->matches(cursorPointer)) {
125                 m_isButton = true;
126                 break;
127             }
128         }
129     }
130     m_viewImpl->gButtonMutex.unlock();
131 }
132 
setup()133 bool CursorRing::setup()
134 {
135     m_node->cursorRings(m_frame, &m_rings);
136     if (!m_rings.size()) {
137         DBG_NAV_LOG("!rings.size()");
138         m_viewImpl->m_hasCursorBounds = false;
139         return false;
140     }
141     setIsButton(m_node);
142     m_bounds = m_node->bounds(m_frame);
143     m_viewImpl->updateCursorBounds(m_root, m_frame, m_node);
144 
145     bool useHitBounds = m_node->useHitBounds();
146     if (useHitBounds)
147         m_bounds = m_node->hitBounds(m_frame);
148     if (useHitBounds || m_node->useBounds()) {
149         m_rings.clear();
150         m_rings.append(m_bounds);
151     }
152     m_absBounds = m_node->bounds(m_frame);
153     const CachedColor& colors = m_frame->color(m_node);
154     m_bounds.inflate(SkScalarCeil(colors.outerWidth()));
155     m_absBounds.inflate(SkScalarCeil(colors.outerWidth()));
156     if (!m_node->hasCursorRing() || (m_node->isPlugin() && m_node->isFocus()))
157         return false;
158 #if DEBUG_NAV_UI
159     const WebCore::IntRect& ring = m_rings[0];
160     DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) pressed=%s rings=%d"
161         " (%d, %d, %d, %d) isPlugin=%s",
162         m_node->index(), m_node->nodePointer(),
163         m_isPressed ? "true" : "false",
164         m_rings.size(), ring.x(), ring.y(), ring.width(), ring.height(),
165         m_node->isPlugin() ? "true" : "false");
166     DBG_NAV_LOGD("[%d] inner=%d outer=%d outset=%d radius=%d"
167         " fill=0x%08x pin=0x%08x pout=0x%08x sin=0x%08x sout=0x%08x",
168         m_node->colorIndex(), colors.innerWidth(), colors.outerWidth(),
169         colors.outset(), colors.radius(), colors.fillColor(),
170         colors.pressedInnerColor(), colors.pressedOuterColor(),
171         colors.selectedInnerColor(), colors.selectedInnerColor());
172 #endif
173     return true;
174 }
175 
176 }
177