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 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 112 void CursorRing::setIsButton(const CachedNode* node) 113 { 114 m_isButton = false; 115 } 116 117 bool CursorRing::setup() 118 { 119 m_node->cursorRings(m_frame, &m_rings); 120 if (!m_rings.size()) { 121 DBG_NAV_LOG("!rings.size()"); 122 m_viewImpl->m_hasCursorBounds = false; 123 return false; 124 } 125 setIsButton(m_node); 126 m_bounds = m_node->bounds(m_frame); 127 m_viewImpl->updateCursorBounds(m_root, m_frame, m_node); 128 129 bool useHitBounds = m_node->useHitBounds(); 130 if (useHitBounds) 131 m_bounds = m_node->hitBounds(m_frame); 132 if (useHitBounds || m_node->useBounds()) { 133 m_rings.clear(); 134 m_rings.append(m_bounds); 135 } 136 m_absBounds = m_node->bounds(m_frame); 137 const CachedColor& colors = m_frame->color(m_node); 138 m_bounds.inflate(SkScalarCeil(colors.outerWidth())); 139 m_absBounds.inflate(SkScalarCeil(colors.outerWidth())); 140 if (!m_node->hasCursorRing() || (m_node->isPlugin() && m_node->isFocus())) 141 return false; 142 #if DEBUG_NAV_UI 143 const WebCore::IntRect& ring = m_rings[0]; 144 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) pressed=%s rings=%d" 145 " (%d, %d, %d, %d) isPlugin=%s", 146 m_node->index(), m_node->nodePointer(), 147 m_isPressed ? "true" : "false", 148 m_rings.size(), ring.x(), ring.y(), ring.width(), ring.height(), 149 m_node->isPlugin() ? "true" : "false"); 150 DBG_NAV_LOGD("[%d] inner=%d outer=%d outset=%d radius=%d" 151 " fill=0x%08x pin=0x%08x pout=0x%08x sin=0x%08x sout=0x%08x", 152 m_node->colorIndex(), colors.innerWidth(), colors.outerWidth(), 153 colors.outset(), colors.radius(), colors.fillColor(), 154 colors.pressedInnerColor(), colors.pressedOuterColor(), 155 colors.selectedInnerColor(), colors.selectedInnerColor()); 156 #endif 157 return true; 158 } 159 160 } 161