gfx/skia/trunk/src/core/SkScan_Hairline.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2006 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include "SkScan.h"
michael@0 11 #include "SkBlitter.h"
michael@0 12 #include "SkRasterClip.h"
michael@0 13 #include "SkFDot6.h"
michael@0 14 #include "SkLineClipper.h"
michael@0 15
michael@0 16 static void horiline(int x, int stopx, SkFixed fy, SkFixed dy,
michael@0 17 SkBlitter* blitter) {
michael@0 18 SkASSERT(x < stopx);
michael@0 19
michael@0 20 do {
michael@0 21 blitter->blitH(x, fy >> 16, 1);
michael@0 22 fy += dy;
michael@0 23 } while (++x < stopx);
michael@0 24 }
michael@0 25
michael@0 26 static void vertline(int y, int stopy, SkFixed fx, SkFixed dx,
michael@0 27 SkBlitter* blitter) {
michael@0 28 SkASSERT(y < stopy);
michael@0 29
michael@0 30 do {
michael@0 31 blitter->blitH(fx >> 16, y, 1);
michael@0 32 fx += dx;
michael@0 33 } while (++y < stopy);
michael@0 34 }
michael@0 35
michael@0 36 #ifdef SK_DEBUG
michael@0 37 static bool canConvertFDot6ToFixed(SkFDot6 x) {
michael@0 38 const int maxDot6 = SK_MaxS32 >> (16 - 6);
michael@0 39 return SkAbs32(x) <= maxDot6;
michael@0 40 }
michael@0 41 #endif
michael@0 42
michael@0 43 void SkScan::HairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
michael@0 44 const SkRegion* clip, SkBlitter* blitter) {
michael@0 45 SkBlitterClipper clipper;
michael@0 46 SkRect r;
michael@0 47 SkIRect clipR, ptsR;
michael@0 48 SkPoint pts[2] = { pt0, pt1 };
michael@0 49
michael@0 50 // We have to pre-clip the line to fit in a SkFixed, so we just chop
michael@0 51 // the line. TODO find a way to actually draw beyond that range.
michael@0 52 {
michael@0 53 SkRect fixedBounds;
michael@0 54 const SkScalar max = SkIntToScalar(32767);
michael@0 55 fixedBounds.set(-max, -max, max, max);
michael@0 56 if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
michael@0 57 return;
michael@0 58 }
michael@0 59 }
michael@0 60
michael@0 61 if (clip) {
michael@0 62 // Perform a clip in scalar space, so we catch huge values which might
michael@0 63 // be missed after we convert to SkFDot6 (overflow)
michael@0 64 r.set(clip->getBounds());
michael@0 65 if (!SkLineClipper::IntersectLine(pts, r, pts)) {
michael@0 66 return;
michael@0 67 }
michael@0 68 }
michael@0 69
michael@0 70 SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
michael@0 71 SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
michael@0 72 SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
michael@0 73 SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
michael@0 74
michael@0 75 SkASSERT(canConvertFDot6ToFixed(x0));
michael@0 76 SkASSERT(canConvertFDot6ToFixed(y0));
michael@0 77 SkASSERT(canConvertFDot6ToFixed(x1));
michael@0 78 SkASSERT(canConvertFDot6ToFixed(y1));
michael@0 79
michael@0 80 if (clip) {
michael@0 81 // now perform clipping again, as the rounding to dot6 can wiggle us
michael@0 82 // our rects are really dot6 rects, but since we've already used
michael@0 83 // lineclipper, we know they will fit in 32bits (26.6)
michael@0 84 const SkIRect& bounds = clip->getBounds();
michael@0 85
michael@0 86 clipR.set(SkIntToFDot6(bounds.fLeft), SkIntToFDot6(bounds.fTop),
michael@0 87 SkIntToFDot6(bounds.fRight), SkIntToFDot6(bounds.fBottom));
michael@0 88 ptsR.set(x0, y0, x1, y1);
michael@0 89 ptsR.sort();
michael@0 90
michael@0 91 // outset the right and bottom, to account for how hairlines are
michael@0 92 // actually drawn, which may hit the pixel to the right or below of
michael@0 93 // the coordinate
michael@0 94 ptsR.fRight += SK_FDot6One;
michael@0 95 ptsR.fBottom += SK_FDot6One;
michael@0 96
michael@0 97 if (!SkIRect::Intersects(ptsR, clipR)) {
michael@0 98 return;
michael@0 99 }
michael@0 100 if (clip->isRect() && clipR.contains(ptsR)) {
michael@0 101 clip = NULL;
michael@0 102 } else {
michael@0 103 blitter = clipper.apply(blitter, clip);
michael@0 104 }
michael@0 105 }
michael@0 106
michael@0 107 SkFDot6 dx = x1 - x0;
michael@0 108 SkFDot6 dy = y1 - y0;
michael@0 109
michael@0 110 if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal
michael@0 111 if (x0 > x1) { // we want to go left-to-right
michael@0 112 SkTSwap<SkFDot6>(x0, x1);
michael@0 113 SkTSwap<SkFDot6>(y0, y1);
michael@0 114 }
michael@0 115 int ix0 = SkFDot6Round(x0);
michael@0 116 int ix1 = SkFDot6Round(x1);
michael@0 117 if (ix0 == ix1) {// too short to draw
michael@0 118 return;
michael@0 119 }
michael@0 120
michael@0 121 SkFixed slope = SkFixedDiv(dy, dx);
michael@0 122 SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6);
michael@0 123
michael@0 124 horiline(ix0, ix1, startY, slope, blitter);
michael@0 125 } else { // mostly vertical
michael@0 126 if (y0 > y1) { // we want to go top-to-bottom
michael@0 127 SkTSwap<SkFDot6>(x0, x1);
michael@0 128 SkTSwap<SkFDot6>(y0, y1);
michael@0 129 }
michael@0 130 int iy0 = SkFDot6Round(y0);
michael@0 131 int iy1 = SkFDot6Round(y1);
michael@0 132 if (iy0 == iy1) { // too short to draw
michael@0 133 return;
michael@0 134 }
michael@0 135
michael@0 136 SkFixed slope = SkFixedDiv(dx, dy);
michael@0 137 SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6);
michael@0 138
michael@0 139 vertline(iy0, iy1, startX, slope, blitter);
michael@0 140 }
michael@0 141 }
michael@0 142
michael@0 143 // we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
michael@0 144 // and double-hit the top-left.
michael@0 145 // TODO: handle huge coordinates on rect (before calling SkScalarToFixed)
michael@0 146 void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
michael@0 147 SkBlitter* blitter) {
michael@0 148 SkAAClipBlitterWrapper wrapper;
michael@0 149 SkBlitterClipper clipper;
michael@0 150 SkIRect r;
michael@0 151
michael@0 152 r.set(SkScalarToFixed(rect.fLeft) >> 16,
michael@0 153 SkScalarToFixed(rect.fTop) >> 16,
michael@0 154 (SkScalarToFixed(rect.fRight) >> 16) + 1,
michael@0 155 (SkScalarToFixed(rect.fBottom) >> 16) + 1);
michael@0 156
michael@0 157 if (clip.quickReject(r)) {
michael@0 158 return;
michael@0 159 }
michael@0 160 if (!clip.quickContains(r)) {
michael@0 161 const SkRegion* clipRgn;
michael@0 162 if (clip.isBW()) {
michael@0 163 clipRgn = &clip.bwRgn();
michael@0 164 } else {
michael@0 165 wrapper.init(clip, blitter);
michael@0 166 clipRgn = &wrapper.getRgn();
michael@0 167 blitter = wrapper.getBlitter();
michael@0 168 }
michael@0 169 blitter = clipper.apply(blitter, clipRgn);
michael@0 170 }
michael@0 171
michael@0 172 int width = r.width();
michael@0 173 int height = r.height();
michael@0 174
michael@0 175 if ((width | height) == 0) {
michael@0 176 return;
michael@0 177 }
michael@0 178 if (width <= 2 || height <= 2) {
michael@0 179 blitter->blitRect(r.fLeft, r.fTop, width, height);
michael@0 180 return;
michael@0 181 }
michael@0 182 // if we get here, we know we have 4 segments to draw
michael@0 183 blitter->blitH(r.fLeft, r.fTop, width); // top
michael@0 184 blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2); // left
michael@0 185 blitter->blitRect(r.fRight - 1, r.fTop + 1, 1, height - 2); // right
michael@0 186 blitter->blitH(r.fLeft, r.fBottom - 1, width); // bottom
michael@0 187 }
michael@0 188
michael@0 189 ///////////////////////////////////////////////////////////////////////////////
michael@0 190
michael@0 191 #include "SkPath.h"
michael@0 192 #include "SkGeometry.h"
michael@0 193
michael@0 194 static int compute_int_quad_dist(const SkPoint pts[3]) {
michael@0 195 // compute the vector between the control point ([1]) and the middle of the
michael@0 196 // line connecting the start and end ([0] and [2])
michael@0 197 SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX;
michael@0 198 SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY;
michael@0 199 // we want everyone to be positive
michael@0 200 dx = SkScalarAbs(dx);
michael@0 201 dy = SkScalarAbs(dy);
michael@0 202 // convert to whole pixel values (use ceiling to be conservative)
michael@0 203 int idx = SkScalarCeilToInt(dx);
michael@0 204 int idy = SkScalarCeilToInt(dy);
michael@0 205 // use the cheap approx for distance
michael@0 206 if (idx > idy) {
michael@0 207 return idx + (idy >> 1);
michael@0 208 } else {
michael@0 209 return idy + (idx >> 1);
michael@0 210 }
michael@0 211 }
michael@0 212
michael@0 213 typedef void (*LineProc)(const SkPoint&, const SkPoint&, const SkRegion*,
michael@0 214 SkBlitter*);
michael@0 215
michael@0 216 static void hairquad(const SkPoint pts[3], const SkRegion* clip,
michael@0 217 SkBlitter* blitter, int level, LineProc lineproc) {
michael@0 218 if (level > 0) {
michael@0 219 SkPoint tmp[5];
michael@0 220
michael@0 221 SkChopQuadAtHalf(pts, tmp);
michael@0 222 hairquad(tmp, clip, blitter, level - 1, lineproc);
michael@0 223 hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
michael@0 224 } else {
michael@0 225 lineproc(pts[0], pts[2], clip, blitter);
michael@0 226 }
michael@0 227 }
michael@0 228
michael@0 229 static void haircubic(const SkPoint pts[4], const SkRegion* clip,
michael@0 230 SkBlitter* blitter, int level, LineProc lineproc) {
michael@0 231 if (level > 0) {
michael@0 232 SkPoint tmp[7];
michael@0 233
michael@0 234 SkChopCubicAt(pts, tmp, SK_Scalar1/2);
michael@0 235 haircubic(tmp, clip, blitter, level - 1, lineproc);
michael@0 236 haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
michael@0 237 } else {
michael@0 238 lineproc(pts[0], pts[3], clip, blitter);
michael@0 239 }
michael@0 240 }
michael@0 241
michael@0 242 #define kMaxCubicSubdivideLevel 6
michael@0 243 #define kMaxQuadSubdivideLevel 5
michael@0 244
michael@0 245 static int compute_quad_level(const SkPoint pts[3]) {
michael@0 246 int d = compute_int_quad_dist(pts);
michael@0 247 /* quadratics approach the line connecting their start and end points
michael@0 248 4x closer with each subdivision, so we compute the number of
michael@0 249 subdivisions to be the minimum need to get that distance to be less
michael@0 250 than a pixel.
michael@0 251 */
michael@0 252 int level = (33 - SkCLZ(d)) >> 1;
michael@0 253 // sanity check on level (from the previous version)
michael@0 254 if (level > kMaxQuadSubdivideLevel) {
michael@0 255 level = kMaxQuadSubdivideLevel;
michael@0 256 }
michael@0 257 return level;
michael@0 258 }
michael@0 259
michael@0 260 static void hair_path(const SkPath& path, const SkRasterClip& rclip,
michael@0 261 SkBlitter* blitter, LineProc lineproc) {
michael@0 262 if (path.isEmpty()) {
michael@0 263 return;
michael@0 264 }
michael@0 265
michael@0 266 SkAAClipBlitterWrapper wrap;
michael@0 267 const SkRegion* clip = NULL;
michael@0 268
michael@0 269 {
michael@0 270 SkIRect ibounds;
michael@0 271 path.getBounds().roundOut(&ibounds);
michael@0 272 ibounds.inset(-1, -1);
michael@0 273
michael@0 274 if (rclip.quickReject(ibounds)) {
michael@0 275 return;
michael@0 276 }
michael@0 277 if (!rclip.quickContains(ibounds)) {
michael@0 278 if (rclip.isBW()) {
michael@0 279 clip = &rclip.bwRgn();
michael@0 280 } else {
michael@0 281 wrap.init(rclip, blitter);
michael@0 282 blitter = wrap.getBlitter();
michael@0 283 clip = &wrap.getRgn();
michael@0 284 }
michael@0 285 }
michael@0 286 }
michael@0 287
michael@0 288 SkPath::Iter iter(path, false);
michael@0 289 SkPoint pts[4];
michael@0 290 SkPath::Verb verb;
michael@0 291 SkAutoConicToQuads converter;
michael@0 292
michael@0 293 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
michael@0 294 switch (verb) {
michael@0 295 case SkPath::kMove_Verb:
michael@0 296 break;
michael@0 297 case SkPath::kLine_Verb:
michael@0 298 lineproc(pts[0], pts[1], clip, blitter);
michael@0 299 break;
michael@0 300 case SkPath::kQuad_Verb:
michael@0 301 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc);
michael@0 302 break;
michael@0 303 case SkPath::kConic_Verb: {
michael@0 304 // how close should the quads be to the original conic?
michael@0 305 const SkScalar tol = SK_Scalar1 / 4;
michael@0 306 const SkPoint* quadPts = converter.computeQuads(pts,
michael@0 307 iter.conicWeight(), tol);
michael@0 308 for (int i = 0; i < converter.countQuads(); ++i) {
michael@0 309 int level = compute_quad_level(quadPts);
michael@0 310 hairquad(quadPts, clip, blitter, level, lineproc);
michael@0 311 quadPts += 2;
michael@0 312 }
michael@0 313 break;
michael@0 314 }
michael@0 315 case SkPath::kCubic_Verb:
michael@0 316 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc);
michael@0 317 break;
michael@0 318 case SkPath::kClose_Verb:
michael@0 319 break;
michael@0 320 case SkPath::kDone_Verb:
michael@0 321 break;
michael@0 322 }
michael@0 323 }
michael@0 324 }
michael@0 325
michael@0 326 void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip,
michael@0 327 SkBlitter* blitter) {
michael@0 328 hair_path(path, clip, blitter, SkScan::HairLineRgn);
michael@0 329 }
michael@0 330
michael@0 331 void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip,
michael@0 332 SkBlitter* blitter) {
michael@0 333 hair_path(path, clip, blitter, SkScan::AntiHairLineRgn);
michael@0 334 }
michael@0 335
michael@0 336 ///////////////////////////////////////////////////////////////////////////////
michael@0 337
michael@0 338 void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
michael@0 339 const SkRasterClip& clip, SkBlitter* blitter) {
michael@0 340 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
michael@0 341
michael@0 342 if (strokeSize.fX < 0 || strokeSize.fY < 0) {
michael@0 343 return;
michael@0 344 }
michael@0 345
michael@0 346 const SkScalar dx = strokeSize.fX;
michael@0 347 const SkScalar dy = strokeSize.fY;
michael@0 348 SkScalar rx = SkScalarHalf(dx);
michael@0 349 SkScalar ry = SkScalarHalf(dy);
michael@0 350 SkRect outer, tmp;
michael@0 351
michael@0 352 outer.set(r.fLeft - rx, r.fTop - ry,
michael@0 353 r.fRight + rx, r.fBottom + ry);
michael@0 354
michael@0 355 if (r.width() <= dx || r.height() <= dx) {
michael@0 356 SkScan::FillRect(outer, clip, blitter);
michael@0 357 return;
michael@0 358 }
michael@0 359
michael@0 360 tmp.set(outer.fLeft, outer.fTop, outer.fRight, outer.fTop + dy);
michael@0 361 SkScan::FillRect(tmp, clip, blitter);
michael@0 362 tmp.fTop = outer.fBottom - dy;
michael@0 363 tmp.fBottom = outer.fBottom;
michael@0 364 SkScan::FillRect(tmp, clip, blitter);
michael@0 365
michael@0 366 tmp.set(outer.fLeft, outer.fTop + dy, outer.fLeft + dx, outer.fBottom - dy);
michael@0 367 SkScan::FillRect(tmp, clip, blitter);
michael@0 368 tmp.fLeft = outer.fRight - dx;
michael@0 369 tmp.fRight = outer.fRight;
michael@0 370 SkScan::FillRect(tmp, clip, blitter);
michael@0 371 }
michael@0 372
michael@0 373 void SkScan::HairLine(const SkPoint& p0, const SkPoint& p1,
michael@0 374 const SkRasterClip& clip, SkBlitter* blitter) {
michael@0 375 if (clip.isBW()) {
michael@0 376 HairLineRgn(p0, p1, &clip.bwRgn(), blitter);
michael@0 377 } else {
michael@0 378 const SkRegion* clipRgn = NULL;
michael@0 379 SkRect r;
michael@0 380 SkIRect ir;
michael@0 381 r.set(p0.fX, p0.fY, p1.fX, p1.fY);
michael@0 382 r.sort();
michael@0 383 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
michael@0 384 r.roundOut(&ir);
michael@0 385
michael@0 386 SkAAClipBlitterWrapper wrap;
michael@0 387 if (!clip.quickContains(ir)) {
michael@0 388 wrap.init(clip, blitter);
michael@0 389 blitter = wrap.getBlitter();
michael@0 390 clipRgn = &wrap.getRgn();
michael@0 391 }
michael@0 392 HairLineRgn(p0, p1, clipRgn, blitter);
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396 void SkScan::AntiHairLine(const SkPoint& p0, const SkPoint& p1,
michael@0 397 const SkRasterClip& clip, SkBlitter* blitter) {
michael@0 398 if (clip.isBW()) {
michael@0 399 AntiHairLineRgn(p0, p1, &clip.bwRgn(), blitter);
michael@0 400 } else {
michael@0 401 const SkRegion* clipRgn = NULL;
michael@0 402 SkRect r;
michael@0 403 SkIRect ir;
michael@0 404 r.set(p0.fX, p0.fY, p1.fX, p1.fY);
michael@0 405 r.sort();
michael@0 406 r.roundOut(&ir);
michael@0 407 ir.inset(-1, -1);
michael@0 408
michael@0 409 SkAAClipBlitterWrapper wrap;
michael@0 410 if (!clip.quickContains(ir)) {
michael@0 411 wrap.init(clip, blitter);
michael@0 412 blitter = wrap.getBlitter();
michael@0 413 clipRgn = &wrap.getRgn();
michael@0 414 }
michael@0 415 AntiHairLineRgn(p0, p1, clipRgn, blitter);
michael@0 416 }
michael@0 417 }

mercurial