Index: third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp |
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp |
index 80a7b90c9b77fd15493499141bc206560a440f0a..e6e2a3a463ba88be260be1d7924114398eeb4b53 100644 |
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp |
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp |
@@ -18,7 +18,10 @@ |
#include "core/style/AppliedTextDecoration.h" |
#include "platform/graphics/GraphicsContextStateSaver.h" |
#include "platform/graphics/paint/DrawingRecorder.h" |
+#include "platform/graphics/paint/PaintRecord.h" |
+#include "platform/graphics/paint/PaintRecorder.h" |
#include "platform/wtf/Optional.h" |
+#include "third_party/skia/include/effects/SkGradientShader.h" |
namespace blink { |
@@ -1090,19 +1093,135 @@ void InlineTextBoxPainter::PaintDocumentMarkers( |
} |
} |
-static GraphicsContext::DocumentMarkerLineStyle LineStyleForMarkerType( |
- DocumentMarker::MarkerType marker_type) { |
- switch (marker_type) { |
- case DocumentMarker::kSpelling: |
- return GraphicsContext::kDocumentMarkerSpellingLineStyle; |
- case DocumentMarker::kGrammar: |
- return GraphicsContext::kDocumentMarkerGrammarLineStyle; |
- default: |
- ASSERT_NOT_REACHED(); |
- return GraphicsContext::kDocumentMarkerSpellingLineStyle; |
- } |
+namespace { |
+ |
+#if !OS(MACOSX) |
+ |
+sk_sp<PaintRecord> RecordMarker(DocumentMarker::MarkerType marker_type) { |
+ SkColor color = (marker_type == DocumentMarker::kGrammar) |
+ ? SkColorSetRGB(0xC0, 0xC0, 0xC0) |
+ : SK_ColorRED; |
+ |
+ // Record the path equivalent to this legacy pattern: |
+ // X o o X o o X |
+ // o X o o X o |
+ |
+ static const float kW = 4; |
+ static const float kH = 2; |
+ |
+ // Adjust the phase such that f' == 0 is "pixel"-centered |
+ // (for optimal rasterization at native rez). |
+ SkPath path; |
+ path.moveTo(kW * -3 / 8, kH * 3 / 4); |
+ path.cubicTo(kW * -1 / 8, kH * 3 / 4, |
+ kW * -1 / 8, kH * 1 / 4, |
+ kW * 1 / 8, kH * 1 / 4); |
+ path.cubicTo(kW * 3 / 8, kH * 1 / 4, |
+ kW * 3 / 8, kH * 3 / 4, |
+ kW * 5 / 8, kH * 3 / 4); |
+ path.cubicTo(kW * 7 / 8, kH * 3 / 4, |
+ kW * 7 / 8, kH * 1 / 4, |
+ kW * 9 / 8, kH * 1 / 4); |
+ |
+ PaintFlags flags; |
+ flags.setAntiAlias(true); |
+ flags.setColor(color); |
+ flags.setStyle(PaintFlags::kStroke_Style); |
+ flags.setStrokeWidth(kH * 1 / 2); |
+ |
+ PaintRecorder recorder; |
+ recorder.beginRecording(kW, kH); |
+ recorder.getRecordingCanvas()->drawPath(path, flags); |
+ |
+ return recorder.finishRecordingAsPicture(); |
} |
+#else // OS(MACOSX) |
+ |
+sk_sp<PaintRecord> RecordMarker(DocumentMarker::MarkerType marker_type) { |
+ SkColor color = (marker_type == DocumentMarker::kGrammar) |
+ ? SkColorSetRGB(0x6B, 0x6B, 0x6B) |
+ : SkColorSetRGB(0xFB, 0x2D, 0x1D); |
+ |
+ // Match the artwork used by the Mac. |
+ static const float kW = 4; |
+ static const float kH = 3; |
+ static const float kR = 1.5f; |
+ |
+ // top->bottom translucent gradient. |
+ const SkColor colors[2] = { |
+ SkColorSetARGB(0x48, |
+ SkColorGetR(color), |
+ SkColorGetG(color), |
+ SkColorGetB(color)), |
+ color |
+ }; |
+ const SkPoint pts[2] = { |
+ SkPoint::Make(0, 0), |
+ SkPoint::Make(0, 2 * kR) |
+ }; |
+ |
+ PaintFlags flags; |
+ flags.setAntiAlias(true); |
+ flags.setColor(color); |
+ flags.setShader(SkGradientShader::MakeLinear( |
+ pts, colors, nullptr, ARRAY_SIZE(colors), SkShader::kClamp_TileMode)); |
+ PaintRecorder recorder; |
+ recorder.beginRecording(kW, kH); |
+ recorder.getRecordingCanvas()->drawCircle(kR, kR, kR, flags); |
+ |
+ return recorder.finishRecordingAsPicture(); |
+} |
+ |
+#endif // OS(MACOSX) |
+ |
+void DrawDocumentMarker(GraphicsContext& context, |
+ const FloatPoint& pt, |
+ float width, |
+ DocumentMarker::MarkerType marker_type, |
+ float zoom) { |
+ DCHECK(marker_type == DocumentMarker::kSpelling || |
+ marker_type == DocumentMarker::kGrammar); |
+ |
+ DEFINE_STATIC_LOCAL(PaintRecord*, spelling_marker, |
+ (RecordMarker(DocumentMarker::kSpelling).release())); |
+ DEFINE_STATIC_LOCAL(PaintRecord*, grammar_marker, |
+ (RecordMarker(DocumentMarker::kGrammar).release())); |
+ const auto& marker = marker_type == DocumentMarker::kSpelling |
+ ? spelling_marker |
+ : grammar_marker; |
+ |
+ // Position already includes zoom and device scale factor. |
+ SkScalar origin_x = WebCoreFloatToSkScalar(pt.X()); |
+ SkScalar origin_y = WebCoreFloatToSkScalar(pt.Y()); |
+ |
+#if OS(MACOSX) |
+ // Make sure to draw only complete dots, and finish inside the marked text. |
+ width -= fmodf(width, marker->cullRect().width() * zoom); |
+#else |
+ // Offset it vertically by 1 so that there's some space under the text. |
+ origin_y += 1; |
+#endif |
+ |
+ const auto rect = SkRect::MakeWH(width, marker->cullRect().height() * zoom); |
+ const auto local_matrix = SkMatrix::MakeScale(zoom, zoom); |
+ |
+ PaintFlags flags; |
+ flags.setAntiAlias(true); |
+ flags.setShader(WrapSkShader(MakePaintShaderRecord( |
+ sk_ref_sp(marker), SkShader::kRepeat_TileMode, SkShader::kClamp_TileMode, |
+ &local_matrix, nullptr))); |
+ |
+ // Apply the origin translation as a global transform. This ensures that the |
+ // shader local matrix depends solely on zoom => Skia can reuse the same |
+ // cached tile for all markers at a given zoom level. |
+ GraphicsContextStateSaver saver(context); |
+ context.Translate(origin_x, origin_y); |
+ context.DrawRect(rect, flags); |
+} |
+ |
+} // anonymous ns |
+ |
void InlineTextBoxPainter::PaintDocumentMarker(GraphicsContext& context, |
const LayoutPoint& box_origin, |
const DocumentMarker& marker, |
@@ -1186,11 +1305,10 @@ void InlineTextBoxPainter::PaintDocumentMarker(GraphicsContext& context, |
// prevent a big gap. |
underline_offset = baseline + 2; |
} |
- context.DrawLineForDocumentMarker( |
- FloatPoint((box_origin.X() + start).ToFloat(), |
- (box_origin.Y() + underline_offset).ToFloat()), |
- width.ToFloat(), LineStyleForMarkerType(marker.GetType()), |
- style.EffectiveZoom()); |
+ DrawDocumentMarker(context, |
+ FloatPoint((box_origin.X() + start).ToFloat(), |
+ (box_origin.Y() + underline_offset).ToFloat()), |
+ width.ToFloat(), marker.GetType(), style.EffectiveZoom()); |
} |
template <InlineTextBoxPainter::PaintOptions options> |