summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
blob: 8e85976b57aa25269aded2bf943c9221a095ab16 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h"

#include <memory>
#include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"

namespace blink {

PaintRenderingContext2D::PaintRenderingContext2D(
    const IntSize& container_size,
    const PaintRenderingContext2DSettings* context_settings,
    float zoom,
    float device_scale_factor)
    : container_size_(container_size),
      context_settings_(context_settings),
      effective_zoom_(zoom) {
  InitializePaintRecorder();

  clip_antialiasing_ = kAntiAliased;
  ModifiableState().SetShouldAntialias(true);

  GetPaintCanvas()->clear(context_settings->alpha() ? SK_ColorTRANSPARENT
                                                    : SK_ColorBLACK);
  did_record_draw_commands_in_paint_recorder_ = true;
}

void PaintRenderingContext2D::InitializePaintRecorder() {
  paint_recorder_ = std::make_unique<PaintRecorder>();
  cc::PaintCanvas* canvas = paint_recorder_->beginRecording(
      container_size_.Width(), container_size_.Height());

  // Always save an initial frame, to support resetting the top level matrix
  // and clip.
  canvas->save();

  scale(effective_zoom_, effective_zoom_);

  did_record_draw_commands_in_paint_recorder_ = false;
}

void PaintRenderingContext2D::DidDraw(const SkIRect&) {
  did_record_draw_commands_in_paint_recorder_ = true;
}

int PaintRenderingContext2D::Width() const {
  return container_size_.Width();
}

int PaintRenderingContext2D::Height() const {
  return container_size_.Height();
}

bool PaintRenderingContext2D::ParseColorOrCurrentColor(
    Color& color,
    const String& color_string) const {
  // We ignore "currentColor" for PaintRenderingContext2D and just make it
  // "black". "currentColor" can be emulated by having "color" as an input
  // property for the css-paint-api.
  // https://github.com/w3c/css-houdini-drafts/issues/133
  return ::blink::ParseColorOrCurrentColor(color, color_string, nullptr);
}

// We need to account for the |effective_zoom_| for shadow effects only, and not
// for line width. This is because the line width is affected by skia's current
// transform matrix (CTM) while shadows are not. The skia's CTM combines both
// the canvas context transform and the CSS layout transform. That means, the
// |effective_zoom_| is implictly applied to line width through CTM.
double PaintRenderingContext2D::shadowBlur() const {
  return BaseRenderingContext2D::shadowBlur() / effective_zoom_;
}

void PaintRenderingContext2D::setShadowBlur(double blur) {
  BaseRenderingContext2D::setShadowBlur(blur * effective_zoom_);
}

double PaintRenderingContext2D::shadowOffsetX() const {
  return BaseRenderingContext2D::shadowOffsetX() / effective_zoom_;
}

void PaintRenderingContext2D::setShadowOffsetX(double x) {
  BaseRenderingContext2D::setShadowOffsetX(x * effective_zoom_);
}

double PaintRenderingContext2D::shadowOffsetY() const {
  return BaseRenderingContext2D::shadowOffsetY() / effective_zoom_;
}

void PaintRenderingContext2D::setShadowOffsetY(double y) {
  BaseRenderingContext2D::setShadowOffsetY(y * effective_zoom_);
}

cc::PaintCanvas* PaintRenderingContext2D::GetPaintCanvas() const {
  DCHECK(paint_recorder_);
  DCHECK(paint_recorder_->getRecordingCanvas());
  return paint_recorder_->getRecordingCanvas();
}

void PaintRenderingContext2D::ValidateStateStackWithCanvas(
    const cc::PaintCanvas* canvas) const {
#if DCHECK_IS_ON()
  if (canvas) {
    DCHECK_EQ(static_cast<size_t>(canvas->getSaveCount()),
              state_stack_.size() + 1);
  }
#endif
}

bool PaintRenderingContext2D::StateHasFilter() {
  return GetState().HasFilterForOffscreenCanvas(IntSize(Width(), Height()),
                                                this);
}

sk_sp<PaintFilter> PaintRenderingContext2D::StateGetFilter() {
  return GetState().GetFilterForOffscreenCanvas(IntSize(Width(), Height()),
                                                this);
}

void PaintRenderingContext2D::WillOverwriteCanvas() {
  previous_frame_.reset();
  if (did_record_draw_commands_in_paint_recorder_) {
    // Discard previous draw commands
    paint_recorder_->finishRecordingAsPicture();
    InitializePaintRecorder();
  }
}

DOMMatrix* PaintRenderingContext2D::getTransform() {
  const TransformationMatrix& t = GetState().GetTransform();
  DOMMatrix* m = DOMMatrix::Create();
  m->setA(t.A() / effective_zoom_);
  m->setB(t.B() / effective_zoom_);
  m->setC(t.C() / effective_zoom_);
  m->setD(t.D() / effective_zoom_);
  m->setE(t.E() / effective_zoom_);
  m->setF(t.F() / effective_zoom_);
  return m;
}

// On a platform where zoom_for_dsf is not enabled, the recording canvas has its
// logic to account for the device scale factor. Therefore, when the transform
// of the canvas happen, we must account for the effective_zoom_ such that the
// recording canvas would have the correct behavior.
//
// The BaseRenderingContext2D::setTransform calls resetTransform, so integrating
// the effective_zoom_ in here instead of setTransform, to avoid integrating it
// twice if we have resetTransform and setTransform API calls.
void PaintRenderingContext2D::resetTransform() {
  BaseRenderingContext2D::resetTransform();
  BaseRenderingContext2D::transform(effective_zoom_, 0, 0, effective_zoom_, 0,
                                    0);
}

sk_sp<PaintRecord> PaintRenderingContext2D::GetRecord() {
  if (!did_record_draw_commands_in_paint_recorder_ && !!previous_frame_) {
    return previous_frame_;  // Reuse the previous frame
  }

  CHECK(paint_recorder_);
  DCHECK(paint_recorder_->getRecordingCanvas());
  previous_frame_ = paint_recorder_->finishRecordingAsPicture();
  InitializePaintRecorder();
  return previous_frame_;
}

}  // namespace blink