Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp

Issue 2674003002: Scalable spelling/grammar markers (Closed)
Patch Set: formatting Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/graphics/GraphicsContext.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. 2 * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 26 matching lines...) Expand all
37 #include "platform/graphics/paint/PaintRecord.h" 37 #include "platform/graphics/paint/PaintRecord.h"
38 #include "platform/graphics/paint/PaintRecorder.h" 38 #include "platform/graphics/paint/PaintRecorder.h"
39 #include "platform/instrumentation/tracing/TraceEvent.h" 39 #include "platform/instrumentation/tracing/TraceEvent.h"
40 #include "platform/weborigin/KURL.h" 40 #include "platform/weborigin/KURL.h"
41 #include "skia/ext/platform_canvas.h" 41 #include "skia/ext/platform_canvas.h"
42 #include "third_party/skia/include/core/SkAnnotation.h" 42 #include "third_party/skia/include/core/SkAnnotation.h"
43 #include "third_party/skia/include/core/SkColorFilter.h" 43 #include "third_party/skia/include/core/SkColorFilter.h"
44 #include "third_party/skia/include/core/SkData.h" 44 #include "third_party/skia/include/core/SkData.h"
45 #include "third_party/skia/include/core/SkRRect.h" 45 #include "third_party/skia/include/core/SkRRect.h"
46 #include "third_party/skia/include/core/SkRefCnt.h" 46 #include "third_party/skia/include/core/SkRefCnt.h"
47 #include "third_party/skia/include/core/SkUnPreMultiply.h"
Stephen White 2017/03/02 15:06:26 uNit: is this still used anywhere? Maybe it could
f(malita) 2017/03/03 19:16:09 Hmm, nope, how did it sneak in there? :) Thanks,
48 #include "third_party/skia/include/effects/SkGradientShader.h"
47 #include "third_party/skia/include/effects/SkLumaColorFilter.h" 49 #include "third_party/skia/include/effects/SkLumaColorFilter.h"
48 #include "third_party/skia/include/effects/SkPictureImageFilter.h" 50 #include "third_party/skia/include/effects/SkPictureImageFilter.h"
49 #include "third_party/skia/include/pathops/SkPathOps.h" 51 #include "third_party/skia/include/pathops/SkPathOps.h"
50 #include "third_party/skia/include/utils/SkNullCanvas.h" 52 #include "third_party/skia/include/utils/SkNullCanvas.h"
51 #include "wtf/Assertions.h" 53 #include "wtf/Assertions.h"
52 #include "wtf/MathExtras.h" 54 #include "wtf/MathExtras.h"
53 #include <memory> 55 #include <memory>
54 56
55 namespace blink { 57 namespace blink {
56 58
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 PaintFlags fillPaint; 504 PaintFlags fillPaint;
503 fillPaint.setColor(paint.getColor()); 505 fillPaint.setColor(paint.getColor());
504 drawRect(r1, fillPaint); 506 drawRect(r1, fillPaint);
505 drawRect(r2, fillPaint); 507 drawRect(r2, fillPaint);
506 } 508 }
507 509
508 adjustLineToPixelBoundaries(p1, p2, width, penStyle); 510 adjustLineToPixelBoundaries(p1, p2, width, penStyle);
509 m_canvas->drawLine(p1.x(), p1.y(), p2.x(), p2.y(), paint); 511 m_canvas->drawLine(p1.x(), p1.y(), p2.x(), p2.y(), paint);
510 } 512 }
511 513
514 namespace {
515
516 #if !OS(MACOSX)
517
518 sk_sp<SkPicture> recordMarker(GraphicsContext::DocumentMarkerLineStyle style) {
519 SkColor color = (style == GraphicsContext::DocumentMarkerGrammarLineStyle)
520 ? SkColorSetRGB(0xC0, 0xC0, 0xC0)
521 : SK_ColorRED;
522
523 // Record the path equivalent to this legacy pattern:
524 // X o o X o o X
525 // o X o o X o
526
527 static const float kW = 4;
528 static const float kH = 2;
529
530 // Adjust the phase such that f' == 0 is "pixel"-centered
531 // (for optimal rasterization at native rez).
532 SkPath path;
533 path.moveTo(kW * -3 / 8, kH * 3 / 4);
534 path.cubicTo(kW * -1 / 8, kH * 3 / 4,
535 kW * -1 / 8, kH * 1 / 4,
536 kW * 1 / 8, kH * 1 / 4);
537 path.cubicTo(kW * 3 / 8, kH * 1 / 4,
538 kW * 3 / 8, kH * 3 / 4,
539 kW * 5 / 8, kH * 3 / 4);
540 path.cubicTo(kW * 7 / 8, kH * 3 / 4,
541 kW * 7 / 8, kH * 1 / 4,
542 kW * 9 / 8, kH * 1 / 4);
543
544 SkPaint paint;
545 paint.setAntiAlias(true);
546 paint.setColor(color);
547 paint.setStyle(SkPaint::kStroke_Style);
548 paint.setStrokeWidth(kH * 1 / 2);
549
550 SkPictureRecorder recorder;
551 recorder.beginRecording(kW, kH);
552 recorder.getRecordingCanvas()->drawPath(path, paint);
553
554 return recorder.finishRecordingAsPicture();
555 }
556
557 #else // OS(MACOSX)
558
559 sk_sp<SkPicture> recordMarker(GraphicsContext::DocumentMarkerLineStyle style) {
560 SkColor color = (style == GraphicsContext::DocumentMarkerGrammarLineStyle)
561 ? SkColorSetRGB(0x6B, 0x6B, 0x6B)
562 : SkColorSetRGB(0xFB, 0x2D, 0x1D);
563
564 // Match the artwork used by the Mac.
565 static const float kW = 4;
566 static const float kH = 3;
567 static const float kR = 1.5f;
568
569 // top->bottom translucent gradient.
570 const SkColor colors[2] = {
571 SkColorSetARGB(0x48,
572 SkColorGetR(color),
573 SkColorGetG(color),
574 SkColorGetB(color)),
575 color
576 };
577 const SkPoint pts[2] = {
578 SkPoint::Make(0, 0),
579 SkPoint::Make(0, 2 * kR)
580 };
581
582 SkPaint paint;
583 paint.setAntiAlias(true);
584 paint.setColor(color);
585 paint.setShader(SkGradientShader::MakeLinear(pts,
586 colors,
587 nullptr,
588 ARRAY_SIZE(colors),
589 SkShader::kClamp_TileMode));
590 SkPictureRecorder recorder;
591 recorder.beginRecording(kW, kH);
592 recorder.getRecordingCanvas()->drawCircle(kR, kR, kR, paint);
593
594 return recorder.finishRecordingAsPicture();
595 }
596
597 #endif // OS(MACOSX)
598
599 } // anonymous ns
600
512 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt, 601 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& pt,
513 float width, 602 float width,
514 DocumentMarkerLineStyle style, 603 DocumentMarkerLineStyle style,
515 float zoom) { 604 float zoom) {
516 if (contextDisabled()) 605 if (contextDisabled())
517 return; 606 return;
518 607
519 // Use 2x resources for a device scale factor of 1.5 or above. 608 DEFINE_STATIC_LOCAL(SkPicture*, spellingMarker,
520 // This modifes the bitmaps used for the marker, not the overall 609 (recordMarker(DocumentMarkerSpellingLineStyle).release())) ;
521 // scaling of the marker. 610 DEFINE_STATIC_LOCAL(SkPicture*, grammarMarker,
522 int deviceScaleFactor = m_deviceScaleFactor * zoom > 1.5f ? 2 : 1; 611 (recordMarker(DocumentMarkerGrammarLineStyle).release()));
612 const auto& marker = style == DocumentMarkerSpellingLineStyle
613 ? spellingMarker
614 : grammarMarker;
523 615
524 // Create the pattern we'll use to draw the underline.
525 int index = style == DocumentMarkerGrammarLineStyle ? 1 : 0;
526 static SkBitmap* misspellBitmap1x[2] = {0, 0};
527 static SkBitmap* misspellBitmap2x[2] = {0, 0};
528 SkBitmap** misspellBitmap =
529 deviceScaleFactor == 2 ? misspellBitmap2x : misspellBitmap1x;
530 if (!misspellBitmap[index]) {
531 #if OS(MACOSX)
532 // Match the artwork used by the Mac.
533 const int rowPixels = 4 * deviceScaleFactor;
534 const int colPixels = 3 * deviceScaleFactor;
535 SkBitmap bitmap;
536 if (!bitmap.tryAllocN32Pixels(rowPixels, colPixels))
537 return;
538
539 bitmap.eraseARGB(0, 0, 0, 0);
540 const uint32_t transparentColor = 0x00000000;
541
542 if (deviceScaleFactor == 1) {
543 const uint32_t colors[2][6] = {{0x2a2a0600, 0x57571000, 0xa8a81b00,
544 0xbfbf1f00, 0x70701200, 0xe0e02400},
545 {0x2a0f0f0f, 0x571e1e1e, 0xa83d3d3d,
546 0xbf454545, 0x70282828, 0xe0515151}};
547
548 // Pattern: a b a a b a
549 // c d c c d c
550 // e f e e f e
551 for (int x = 0; x < colPixels; ++x) {
552 uint32_t* row = bitmap.getAddr32(0, x);
553 row[0] = colors[index][x * 2];
554 row[1] = colors[index][x * 2 + 1];
555 row[2] = colors[index][x * 2];
556 row[3] = transparentColor;
557 }
558 } else if (deviceScaleFactor == 2) {
559 const uint32_t colors[2][18] = {
560 {0x0a090101, 0x33320806, 0x55540f0a, 0x37360906, 0x6e6c120c,
561 0x6e6c120c, 0x7674140d, 0x8d8b1810, 0x8d8b1810, 0x96941a11,
562 0xb3b01f15, 0xb3b01f15, 0x6d6b130c, 0xd9d62619, 0xd9d62619,
563 0x19180402, 0x7c7a150e, 0xcecb2418},
564 {0x0a020202, 0x33141414, 0x55232323, 0x37161616, 0x6e2e2e2e,
565 0x6e2e2e2e, 0x76313131, 0x8d3a3a3a, 0x8d3a3a3a, 0x963e3e3e,
566 0xb34b4b4b, 0xb34b4b4b, 0x6d2d2d2d, 0xd95b5b5b, 0xd95b5b5b,
567 0x19090909, 0x7c343434, 0xce575757}};
568
569 // Pattern: a b c c b a
570 // d e f f e d
571 // g h j j h g
572 // k l m m l k
573 // n o p p o n
574 // q r s s r q
575 for (int x = 0; x < colPixels; ++x) {
576 uint32_t* row = bitmap.getAddr32(0, x);
577 row[0] = colors[index][x * 3];
578 row[1] = colors[index][x * 3 + 1];
579 row[2] = colors[index][x * 3 + 2];
580 row[3] = colors[index][x * 3 + 2];
581 row[4] = colors[index][x * 3 + 1];
582 row[5] = colors[index][x * 3];
583 row[6] = transparentColor;
584 row[7] = transparentColor;
585 }
586 } else
587 ASSERT_NOT_REACHED();
588
589 misspellBitmap[index] = new SkBitmap(bitmap);
590 #else
591 // We use a 2-pixel-high misspelling indicator because that seems to be
592 // what Blink is designed for, and how much room there is in a typical
593 // page for it.
594 const int rowPixels =
595 32 * deviceScaleFactor; // Must be multiple of 4 for pattern below.
596 const int colPixels = 2 * deviceScaleFactor;
597 SkBitmap bitmap;
598 if (!bitmap.tryAllocN32Pixels(rowPixels, colPixels))
599 return;
600
601 bitmap.eraseARGB(0, 0, 0, 0);
602 if (deviceScaleFactor == 1)
603 draw1xMarker(&bitmap, index);
604 else if (deviceScaleFactor == 2)
605 draw2xMarker(&bitmap, index);
606 else
607 ASSERT_NOT_REACHED();
608
609 misspellBitmap[index] = new SkBitmap(bitmap);
610 #endif
611 }
612
613 #if OS(MACOSX)
614 // Position already includes zoom and device scale factor. 616 // Position already includes zoom and device scale factor.
615 SkScalar originX = WebCoreFloatToSkScalar(pt.x()); 617 SkScalar originX = WebCoreFloatToSkScalar(pt.x());
616 SkScalar originY = WebCoreFloatToSkScalar(pt.y()); 618 SkScalar originY = WebCoreFloatToSkScalar(pt.y());
617 619
620 #if OS(MACOSX)
618 // Make sure to draw only complete dots, and finish inside the marked text. 621 // Make sure to draw only complete dots, and finish inside the marked text.
619 float rowPixels = misspellBitmap[index]->width() * zoom / deviceScaleFactor; 622 width -= fmodf(width, marker->cullRect().width() * zoom);
620 float dotCount = floorf(width / rowPixels);
621 width = dotCount * rowPixels;
622 #else 623 #else
623 SkScalar originX = WebCoreFloatToSkScalar(pt.x());
624
625 // Offset it vertically by 1 so that there's some space under the text. 624 // Offset it vertically by 1 so that there's some space under the text.
626 SkScalar originY = WebCoreFloatToSkScalar(pt.y()) + 1; 625 originY += 1;
627 #endif 626 #endif
628 627
629 SkMatrix localMatrix; 628 const auto rect = SkRect::MakeWH(width, marker->cullRect().height() * zoom);
630 localMatrix.setScale(zoom / deviceScaleFactor, zoom / deviceScaleFactor); 629 const auto localMatrix = SkMatrix::MakeScale(zoom, zoom);
631 localMatrix.postTranslate(originX, originY);
632 630
633 PaintFlags paint; 631 PaintFlags paint;
634 paint.setShader(WrapSkShader(SkShader::MakeBitmapShader( 632 paint.setAntiAlias(true);
635 *misspellBitmap[index], SkShader::kRepeat_TileMode, 633 paint.setShader(WrapSkShader(
636 SkShader::kRepeat_TileMode, &localMatrix))); 634 SkShader::MakePictureShader(sk_ref_sp(marker),
635 SkShader::kRepeat_TileMode,
636 SkShader::kClamp_TileMode,
637 &localMatrix,
638 nullptr)));
637 639
638 SkRect rect; 640 // Apply the origin translation as a global transform. This ensures that the
639 rect.set( 641 // shader local matrix depends solely on zoom => Skia can reuse the same
640 originX, originY, originX + WebCoreFloatToSkScalar(width), 642 // cached tile for all markers at a given zoom level.
641 originY + 643 SkAutoCanvasRestore acr(m_canvas, true);
642 SkIntToScalar(misspellBitmap[index]->height() / deviceScaleFactor) * 644 m_canvas->translate(originX, originY);
643 zoom); 645 m_canvas->drawRect(rect, paint);
644
645 drawRect(rect, paint);
646 } 646 }
647 647
648 void GraphicsContext::drawLineForText(const FloatPoint& pt, float width) { 648 void GraphicsContext::drawLineForText(const FloatPoint& pt, float width) {
649 if (contextDisabled()) 649 if (contextDisabled())
650 return; 650 return;
651 651
652 if (width <= 0) 652 if (width <= 0)
653 return; 653 return;
654 654
655 PaintFlags paint; 655 PaintFlags paint;
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after
1323 case ColorFilterNone: 1323 case ColorFilterNone:
1324 break; 1324 break;
1325 default: 1325 default:
1326 ASSERT_NOT_REACHED(); 1326 ASSERT_NOT_REACHED();
1327 break; 1327 break;
1328 } 1328 }
1329 1329
1330 return nullptr; 1330 return nullptr;
1331 } 1331 }
1332 1332
1333 #if !OS(MACOSX)
1334 void GraphicsContext::draw2xMarker(SkBitmap* bitmap, int index) {
1335 const SkPMColor lineColor = lineColors(index);
1336 const SkPMColor antiColor1 = antiColors1(index);
1337 const SkPMColor antiColor2 = antiColors2(index);
1338
1339 uint32_t* row1 = bitmap->getAddr32(0, 0);
1340 uint32_t* row2 = bitmap->getAddr32(0, 1);
1341 uint32_t* row3 = bitmap->getAddr32(0, 2);
1342 uint32_t* row4 = bitmap->getAddr32(0, 3);
1343
1344 // Pattern: X0o o0X0o o0
1345 // XX0o o0XXX0o o0X
1346 // o0XXX0o o0XXX0o
1347 // o0X0o o0X0o
1348 const SkPMColor row1Color[] = {lineColor, antiColor1, antiColor2, 0,
1349 0, 0, antiColor2, antiColor1};
1350 const SkPMColor row2Color[] = {lineColor, lineColor, antiColor1, antiColor2,
1351 0, antiColor2, antiColor1, lineColor};
1352 const SkPMColor row3Color[] = {0, antiColor2, antiColor1, lineColor,
1353 lineColor, lineColor, antiColor1, antiColor2};
1354 const SkPMColor row4Color[] = {0, 0, antiColor2, antiColor1,
1355 lineColor, antiColor1, antiColor2, 0};
1356
1357 for (int x = 0; x < bitmap->width() + 8; x += 8) {
1358 int count = std::min(bitmap->width() - x, 8);
1359 if (count > 0) {
1360 memcpy(row1 + x, row1Color, count * sizeof(SkPMColor));
1361 memcpy(row2 + x, row2Color, count * sizeof(SkPMColor));
1362 memcpy(row3 + x, row3Color, count * sizeof(SkPMColor));
1363 memcpy(row4 + x, row4Color, count * sizeof(SkPMColor));
1364 }
1365 }
1366 }
1367
1368 void GraphicsContext::draw1xMarker(SkBitmap* bitmap, int index) {
1369 const uint32_t lineColor = lineColors(index);
1370 const uint32_t antiColor = antiColors2(index);
1371
1372 // Pattern: X o o X o o X
1373 // o X o o X o
1374 uint32_t* row1 = bitmap->getAddr32(0, 0);
1375 uint32_t* row2 = bitmap->getAddr32(0, 1);
1376 for (int x = 0; x < bitmap->width(); x++) {
1377 switch (x % 4) {
1378 case 0:
1379 row1[x] = lineColor;
1380 break;
1381 case 1:
1382 row1[x] = antiColor;
1383 row2[x] = antiColor;
1384 break;
1385 case 2:
1386 row2[x] = lineColor;
1387 break;
1388 case 3:
1389 row1[x] = antiColor;
1390 row2[x] = antiColor;
1391 break;
1392 }
1393 }
1394 }
1395
1396 SkPMColor GraphicsContext::lineColors(int index) {
1397 static const SkPMColor colors[] = {
1398 SkPreMultiplyARGB(0xFF, 0xFF, 0x00, 0x00), // Opaque red.
1399 SkPreMultiplyARGB(0xFF, 0xC0, 0xC0, 0xC0) // Opaque gray.
1400 };
1401
1402 return colors[index];
1403 }
1404
1405 SkPMColor GraphicsContext::antiColors1(int index) {
1406 static const SkPMColor colors[] = {
1407 SkPreMultiplyARGB(0xB0, 0xFF, 0x00, 0x00), // Semitransparent red.
1408 SkPreMultiplyARGB(0xB0, 0xC0, 0xC0, 0xC0) // Semitransparent gray.
1409 };
1410
1411 return colors[index];
1412 }
1413
1414 SkPMColor GraphicsContext::antiColors2(int index) {
1415 static const SkPMColor colors[] = {
1416 SkPreMultiplyARGB(0x60, 0xFF, 0x00, 0x00), // More transparent red
1417 SkPreMultiplyARGB(0x60, 0xC0, 0xC0, 0xC0) // More transparent gray
1418 };
1419
1420 return colors[index];
1421 }
1422 #endif
1423
1424 } // namespace blink 1333 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/graphics/GraphicsContext.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698