OSDN Git Service

Fix extras clipping
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / GLExtras.cpp
1 /*
2  * Copyright 2011, 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 "config.h"
27
28 #include "DrawExtra.h"
29 #include "FindCanvas.h"
30 #include "GLExtras.h"
31 #include "IntRect.h"
32 #include "TilesManager.h"
33 #include "android_graphics.h"
34
35 #include <cutils/log.h>
36 #include <wtf/text/CString.h>
37
38 #undef XLOGC
39 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLExtras", __VA_ARGS__)
40
41 #ifdef DEBUG
42
43 #undef XLOG
44 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLExtras", __VA_ARGS__)
45
46 #else
47
48 #undef XLOG
49 #define XLOG(...)
50
51 #endif // DEBUG
52
53 // Touch ring border width. This is doubled if the ring is not pressed
54 #define RING_BORDER_WIDTH 1
55 // Color of the ring is 0x6633b5e5 (copied from framework's holo_light)
56 #define COLOR_HOLO_LIGHT &m_lightRingTexture, 0x33, 0xb5, 0xe5, 0.4f
57 // Color of the ring is 0x660099cc (copied from framework's holo_dark)
58 #define COLOR_HOLO_DARK &m_darkRingTexture, 0x00, 0x99, 0xcc, 0.6f
59 // Put a cap on the number of matches to draw.  If the current page has more
60 // matches than this, only draw the focused match. This both prevents clutter
61 // on the page and keeps the performance happy
62 #define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
63
64 GLExtras::GLExtras()
65     : m_findOnPage(0)
66     , m_ring(0)
67     , m_drawExtra(0)
68     , m_lightRingTexture(-1)
69     , m_darkRingTexture(-1)
70 {
71 }
72
73 GLExtras::~GLExtras()
74 {
75 }
76
77 void GLExtras::drawRing(SkRect& srcRect, int* texture, int r, int g, int b, float a)
78 {
79     if (*texture == -1)
80         *texture = GLUtils::createSampleColorTexture(r, g, b);
81
82     if (srcRect.fRight <= srcRect.fLeft || srcRect.fBottom <= srcRect.fTop) {
83         // Invalid rect, reject it
84         return;
85     }
86     XLOG("drawQuad [%fx%f, %f, %f]", srcRect.fLeft, srcRect.fTop,
87          srcRect.width(), srcRect.height());
88     TilesManager::instance()->shader()->drawQuad(srcRect, *texture, a);
89 }
90
91 void GLExtras::drawRegion(const SkRegion& region, bool fill,
92                           bool drawBorder, bool useDark)
93 {
94     if (region.isEmpty())
95         return;
96     if (fill) {
97         SkRegion::Iterator rgnIter(region);
98         while (!rgnIter.done()) {
99             const SkIRect& ir = rgnIter.rect();
100             SkRect r;
101             r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
102             if (useDark)
103                 drawRing(r, COLOR_HOLO_DARK);
104             else
105                 drawRing(r, COLOR_HOLO_LIGHT);
106             rgnIter.next();
107         }
108     }
109     if (fill && !drawBorder)
110         return;
111     SkPath path;
112     if (!region.getBoundaryPath(&path))
113         return;
114     SkPath::Iter iter(path, true);
115     SkPath::Verb verb;
116     SkPoint pts[4];
117     SkRegion clip;
118     SkIRect startRect;
119     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
120         if (verb == SkPath::kLine_Verb) {
121             SkRect r;
122             r.set(pts, 2);
123             SkIRect line;
124             int borderWidth = RING_BORDER_WIDTH;
125             if (!fill)
126                 borderWidth *= 2;
127             line.fLeft = r.fLeft - borderWidth;
128             line.fRight = r.fRight + borderWidth;
129             line.fTop = r.fTop - borderWidth;
130             line.fBottom = r.fBottom + borderWidth;
131             if (clip.intersects(line)) {
132                 clip.op(line, SkRegion::kReverseDifference_Op);
133                 if (clip.isEmpty())
134                     continue; // Nothing to draw, continue
135                 line = clip.getBounds();
136                 if (SkIRect::Intersects(startRect, line)) {
137                     clip.op(startRect, SkRegion::kDifference_Op);
138                     if (clip.isEmpty())
139                         continue; // Nothing to draw, continue
140                     line = clip.getBounds();
141                 }
142             } else {
143                 clip.setRect(line);
144             }
145             r.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
146             if (useDark)
147                 drawRing(r, COLOR_HOLO_DARK);
148             else
149                 drawRing(r, COLOR_HOLO_LIGHT);
150             if (startRect.isEmpty()) {
151                 startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
152             }
153         }
154         if (verb == SkPath::kMove_Verb) {
155             startRect.setEmpty();
156         }
157     }
158 }
159
160 void GLExtras::drawCursorRings()
161 {
162     SkRegion region;
163     for (size_t i = 0; i < m_ring->rings().size(); i++) {
164         IntRect rect = m_ring->rings().at(i);
165         if (i == 0)
166             region.setRect(rect);
167         else
168             region.op(rect, SkRegion::kUnion_Op);
169     }
170     drawRegion(region, m_ring->m_isPressed, !m_ring->m_isButton, false);
171 }
172
173 void GLExtras::drawFindOnPage(SkRect& viewport)
174 {
175     WTF::Vector<MatchInfo>* matches = m_findOnPage->matches();
176     XLOG("drawFindOnPage, matches: %p", matches);
177     if (!matches || !m_findOnPage->isCurrentLocationValid())
178         return;
179     int count = matches->size();
180     int current = m_findOnPage->currentMatchIndex();
181     XLOG("match count: %d", count);
182     if (count < MAX_NUMBER_OF_MATCHES_TO_DRAW)
183         for (int i = 0; i < count; i++) {
184             MatchInfo& info = matches->at(i);
185             const SkRegion& region = info.getLocation();
186             SkIRect rect = region.getBounds();
187             if (rect.intersect(viewport.fLeft, viewport.fTop,
188                                viewport.fRight, viewport.fBottom))
189                 drawRegion(region, i == current, false, true);
190 #ifdef DEBUG
191             else
192                 XLOG("Quick rejecting [%dx%d, %d, %d", rect.fLeft, rect.fTop,
193                      rect.width(), rect.height());
194 #endif // DEBUG
195         }
196     else {
197         MatchInfo& info = matches->at(current);
198         drawRegion(info.getLocation(), true, false, true);
199     }
200 }
201
202 void GLExtras::drawGL(IntRect& webViewRect, SkRect& viewport, int titleBarHeight)
203 {
204     if (m_drawExtra) {
205         if (m_drawExtra == m_ring)
206             drawCursorRings();
207         else if (m_drawExtra == m_findOnPage)
208             drawFindOnPage(viewport);
209         else
210             XLOGC("m_drawExtra %p is unknown! (cursor: %p, find: %p",
211                   m_drawExtra, m_ring, m_findOnPage);
212     }
213 }