Remove GraphicsContext::drawConvexPolygon() and GraphicsContext::clipConvexPolygon()
[WebKit-https.git] / Source / WebCore / platform / graphics / displaylists / DisplayListRecorder.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. 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 APPLE INC. ``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 APPLE INC. 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 #include "DisplayListRecorder.h"
28
29 #include "DisplayList.h"
30 #include "DisplayListItems.h"
31 #include "GraphicsContext.h"
32 #include "Logging.h"
33 #include "TextStream.h"
34 #include <wtf/MathExtras.h>
35
36 namespace WebCore {
37 namespace DisplayList {
38
39 Recorder::Recorder(GraphicsContext& context, DisplayList& displayList, const FloatRect& initialClip, const AffineTransform& baseCTM)
40     : m_graphicsContext(context)
41     , m_displayList(displayList)
42 {
43     LOG_WITH_STREAM(DisplayLists, stream << "\nRecording with clip " << initialClip);
44
45     // FIXME: Hook up recorder in the GraphicsContext.
46     // m_graphicsContext.setDisplayListRecorder(this);
47     m_stateStack.append(ContextState(baseCTM, initialClip));
48 }
49
50 Recorder::~Recorder()
51 {
52     ASSERT(m_stateStack.size() == 1); // If this fires, it indicates mismatched save/restore.
53     LOG(DisplayLists, "Recorded display list:\n%s", m_displayList.description().data());
54 }
55
56 void Recorder::willAppendItem(const Item& item)
57 {
58     if (item.isDrawingItem()
59 #if USE(CG)
60         || item.type() == ItemType::ApplyStrokePattern || item.type() == ItemType::ApplyStrokePattern
61 #endif
62     ) {
63         GraphicsContextStateChange& stateChanges = currentState().stateChange;
64         GraphicsContextState::StateChangeFlags changesFromLastState = stateChanges.changesFromState(currentState().lastDrawingState);
65         if (changesFromLastState) {
66             LOG_WITH_STREAM(DisplayLists, stream << "pre-drawing, saving state " << GraphicsContextStateChange(stateChanges.m_state, changesFromLastState));
67             m_displayList.append(SetState::create(stateChanges.m_state, changesFromLastState));
68             stateChanges.m_changeFlags = 0;
69             currentState().lastDrawingState = stateChanges.m_state;
70         }
71         currentState().wasUsedForDrawing = true;
72     }
73 }
74
75 void Recorder::updateState(const GraphicsContextState& state, GraphicsContextState::StateChangeFlags flags)
76 {
77     currentState().stateChange.accumulate(state, flags);
78 }
79
80 void Recorder::clearShadow()
81 {
82     appendItem(ClearShadow::create());
83 }
84
85 void Recorder::setLineCap(LineCap lineCap)
86 {
87     appendItem(SetLineCap::create(lineCap));
88 }
89
90 void Recorder::setLineDash(const DashArray& dashArray, float dashOffset)
91 {
92     appendItem(SetLineDash::create(dashArray, dashOffset));
93 }
94
95 void Recorder::setLineJoin(LineJoin lineJoin)
96 {
97     appendItem(SetLineJoin::create(lineJoin));
98 }
99
100 void Recorder::setMiterLimit(float miterLimit)
101 {
102     appendItem(SetMiterLimit::create(miterLimit));
103 }
104
105 void Recorder::drawGlyphs(const Font& font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& startPoint, FontSmoothingMode smoothingMode)
106 {
107     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawGlyphs::create(font, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs, FloatPoint(), toFloatSize(startPoint), smoothingMode)));
108     updateItemExtent(newItem);
109 }
110
111 void Recorder::drawImage(Image& image, const FloatRect& destination, const FloatRect& source, const ImagePaintingOptions& imagePaintingOptions)
112 {
113     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawImage::create(image, destination, source, imagePaintingOptions)));
114     updateItemExtent(newItem);
115 }
116
117 void Recorder::drawTiledImage(Image& image, const FloatRect& destination, const FloatPoint& source, const FloatSize& tileSize, const FloatSize& spacing, const ImagePaintingOptions& imagePaintingOptions)
118 {
119     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawTiledImage::create(image, destination, source, tileSize, spacing, imagePaintingOptions)));
120     updateItemExtent(newItem);
121 }
122
123 #if USE(CG) || USE(CAIRO)
124 void Recorder::drawNativeImage(PassNativeImagePtr imagePtr, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation)
125 {
126     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawNativeImage::create(imagePtr, imageSize, destRect, srcRect, op, blendMode, orientation)));
127     updateItemExtent(newItem);
128 }
129 #endif
130
131 void Recorder::drawTiledImage(Image& image, const FloatRect& destination, const FloatRect& source, const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, const ImagePaintingOptions& imagePaintingOptions)
132 {
133     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawTiledScaledImage::create(image, destination, source, tileScaleFactor, hRule, vRule, imagePaintingOptions)));
134     updateItemExtent(newItem);
135 }
136
137 void Recorder::drawPattern(Image& image, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode)
138 {
139     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawPattern::create(image, tileRect, patternTransform, phase, spacing, op, destRect, blendMode)));
140     updateItemExtent(newItem);
141 }
142
143 void Recorder::save()
144 {
145     appendItem(Save::create());
146     m_stateStack.append(m_stateStack.last().cloneForSave(m_displayList.itemCount() - 1));
147 }
148
149 void Recorder::restore()
150 {
151     if (!m_stateStack.size())
152         return;
153     
154     bool stateUsedForDrawing = currentState().wasUsedForDrawing;
155     size_t saveIndex = currentState().saveItemIndex;
156     
157     m_stateStack.removeLast();
158     // Have to avoid eliding nested Save/Restore when a descendant state contains drawing items.
159     currentState().wasUsedForDrawing |= stateUsedForDrawing;
160
161     if (!stateUsedForDrawing && saveIndex) {
162         // This Save/Restore didn't contain any drawing items. Roll back to just before the last save.
163         m_displayList.removeItemsFromIndex(saveIndex);
164         return;
165     }
166
167     appendItem(Restore::create());
168     
169     if (saveIndex) {
170         Save& saveItem = downcast<Save>(m_displayList.itemAt(saveIndex));
171         saveItem.setRestoreIndex(m_displayList.itemCount() - 1);
172     }
173 }
174
175 void Recorder::translate(float x, float y)
176 {
177     currentState().translate(x, y);
178     appendItem(Translate::create(x, y));
179 }
180
181 void Recorder::rotate(float angleInRadians)
182 {
183     currentState().rotate(angleInRadians);
184     appendItem(Rotate::create(angleInRadians));
185 }
186
187 void Recorder::scale(const FloatSize& size)
188 {
189     currentState().scale(size);
190     appendItem(Scale::create(size));
191 }
192
193 void Recorder::concatCTM(const AffineTransform& transform)
194 {
195     currentState().concatCTM(transform);
196     appendItem(ConcatenateCTM::create(transform));
197 }
198
199 void Recorder::beginTransparencyLayer(float opacity)
200 {
201     DrawingItem& newItem = downcast<DrawingItem>(appendItem(BeginTransparencyLayer::create(opacity)));
202     updateItemExtent(newItem);
203 }
204
205 void Recorder::endTransparencyLayer()
206 {
207     appendItem(EndTransparencyLayer::create());
208 }
209
210 void Recorder::drawRect(const FloatRect& rect, float borderThickness)
211 {
212     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawRect::create(rect, borderThickness)));
213     updateItemExtent(newItem);
214 }
215
216 void Recorder::drawLine(const FloatPoint& point1, const FloatPoint& point2)
217 {
218     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawLine::create(point1, point2)));
219     updateItemExtent(newItem);
220 }
221
222 void Recorder::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing, bool doubleLines, float strokeThickness)
223 {
224     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawLinesForText::create(FloatPoint(), toFloatSize(point), widths, printing, doubleLines, strokeThickness)));
225     updateItemExtent(newItem);
226 }
227
228 void Recorder::drawLineForDocumentMarker(const FloatPoint& point, float width, GraphicsContext::DocumentMarkerLineStyle style)
229 {
230     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawLineForDocumentMarker::create(point, width, style)));
231     updateItemExtent(newItem);
232 }
233
234 void Recorder::drawEllipse(const FloatRect& rect)
235 {
236     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawEllipse::create(rect)));
237     updateItemExtent(newItem);
238 }
239
240 void Recorder::drawPath(const Path& path)
241 {
242     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawPath::create(path)));
243     updateItemExtent(newItem);
244 }
245
246 void Recorder::drawFocusRing(const Path& path, int width, int offset, const Color& color)
247 {
248     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawFocusRingPath::create(path, width, offset, color)));
249     updateItemExtent(newItem);
250 }
251
252 void Recorder::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
253 {
254     DrawingItem& newItem = downcast<DrawingItem>(appendItem(DrawFocusRingRects::create(rects, width, offset, color)));
255     updateItemExtent(newItem);
256 }
257
258 void Recorder::fillRect(const FloatRect& rect)
259 {
260     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillRect::create(rect)));
261     updateItemExtent(newItem);
262 }
263
264 void Recorder::fillRect(const FloatRect& rect, const Color& color)
265 {
266     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillRectWithColor::create(rect, color)));
267     updateItemExtent(newItem);
268 }
269
270 void Recorder::fillRect(const FloatRect& rect, Gradient& gradient)
271 {
272     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillRectWithGradient::create(rect, gradient)));
273     updateItemExtent(newItem);
274 }
275
276 void Recorder::fillRect(const FloatRect& rect, const Color& color, CompositeOperator op, BlendMode blendMode)
277 {
278     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillCompositedRect::create(rect, color, op, blendMode)));
279     updateItemExtent(newItem);
280 }
281
282 void Recorder::fillRoundedRect(const FloatRoundedRect& rect, const Color& color, BlendMode blendMode)
283 {
284     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillRoundedRect::create(rect, color, blendMode)));
285     updateItemExtent(newItem);
286 }
287
288 void Recorder::fillRectWithRoundedHole(const FloatRect& rect, const FloatRoundedRect& roundedHoleRect, const Color& color)
289 {
290     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillRectWithRoundedHole::create(rect, roundedHoleRect, color)));
291     updateItemExtent(newItem);
292 }
293
294 void Recorder::fillPath(const Path& path)
295 {
296     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillPath::create(path)));
297     updateItemExtent(newItem);
298 }
299
300 void Recorder::fillEllipse(const FloatRect& rect)
301 {
302     DrawingItem& newItem = downcast<DrawingItem>(appendItem(FillEllipse::create(rect)));
303     updateItemExtent(newItem);
304 }
305
306 void Recorder::strokeRect(const FloatRect& rect, float lineWidth)
307 {
308     DrawingItem& newItem = downcast<DrawingItem>(appendItem(StrokeRect::create(rect, lineWidth)));
309     updateItemExtent(newItem);
310 }
311
312 void Recorder::strokePath(const Path& path)
313 {
314     DrawingItem& newItem = downcast<DrawingItem>(appendItem(StrokePath::create(path)));
315     updateItemExtent(newItem);
316 }
317
318 void Recorder::strokeEllipse(const FloatRect& rect)
319 {
320     DrawingItem& newItem = downcast<DrawingItem>(appendItem(StrokeEllipse::create(rect)));
321     updateItemExtent(newItem);
322 }
323
324 void Recorder::clearRect(const FloatRect& rect)
325 {
326     DrawingItem& newItem = downcast<DrawingItem>(appendItem(ClearRect::create(rect)));
327     updateItemExtent(newItem);
328 }
329
330 #if USE(CG)
331 void Recorder::applyStrokePattern()
332 {
333     appendItem(ApplyStrokePattern::create());
334 }
335
336 void Recorder::applyFillPattern()
337 {
338     appendItem(ApplyFillPattern::create());
339 }
340 #endif
341
342 void Recorder::clip(const FloatRect& rect)
343 {
344     currentState().clipBounds.intersect(rect);
345     appendItem(Clip::create(rect));
346 }
347
348 void Recorder::clipOut(const FloatRect& rect)
349 {
350     appendItem(ClipOut::create(rect));
351 }
352
353 void Recorder::clipOut(const Path& path)
354 {
355     appendItem(ClipOutToPath::create(path));
356 }
357
358 void Recorder::clipPath(const Path& path, WindRule windRule)
359 {
360     currentState().clipBounds.intersect(path.fastBoundingRect());
361     appendItem(ClipPath::create(path, windRule));
362 }
363
364 void Recorder::applyDeviceScaleFactor(float deviceScaleFactor)
365 {
366     // FIXME: this changes the baseCTM, which will invalidate all of our cached extents.
367     // Assert that it's only called early on?
368     appendItem(ApplyDeviceScaleFactor::create(deviceScaleFactor));
369 }
370
371 Item& Recorder::appendItem(Ref<Item>&& item)
372 {
373     willAppendItem(item.get());
374     return m_displayList.append(WTFMove(item));
375 }
376
377 void Recorder::updateItemExtent(DrawingItem& item) const
378 {
379     if (Optional<FloatRect> rect = item.localBounds(m_graphicsContext))
380         item.setExtent(extentFromLocalBounds(rect.value()));
381 }
382
383 // FIXME: share with ShadowData
384 static inline float shadowPaintingExtent(float blurRadius)
385 {
386     // Blurring uses a Gaussian function whose std. deviation is m_radius/2, and which in theory
387     // extends to infinity. In 8-bit contexts, however, rounding causes the effect to become
388     // undetectable at around 1.4x the radius.
389     const float radiusExtentMultiplier = 1.4;
390     return ceilf(blurRadius * radiusExtentMultiplier);
391 }
392
393 FloatRect Recorder::extentFromLocalBounds(const FloatRect& rect) const
394 {
395     FloatRect bounds = rect;
396     const ContextState& state = currentState();
397
398     FloatSize shadowOffset;
399     float shadowRadius;
400     Color shadowColor;
401     if (m_graphicsContext.getShadow(shadowOffset, shadowRadius, shadowColor)) {
402         FloatRect shadowExtent= bounds;
403         shadowExtent.move(shadowOffset);
404         shadowExtent.inflate(shadowPaintingExtent(shadowRadius));
405         bounds.unite(shadowExtent);
406     }
407     
408     FloatRect clippedExtent = intersection(state.clipBounds, bounds);
409     return state.ctm.mapRect(clippedExtent);
410 }
411
412 const Recorder::ContextState& Recorder::currentState() const
413 {
414     ASSERT(m_stateStack.size());
415     return m_stateStack.last();
416 }
417
418 Recorder::ContextState& Recorder::currentState()
419 {
420     ASSERT(m_stateStack.size());
421     return m_stateStack.last();
422 }
423
424 const AffineTransform& Recorder::ctm() const
425 {
426     return currentState().ctm;
427 }
428
429 const FloatRect& Recorder::clipBounds() const
430 {
431     return currentState().clipBounds;
432 }
433
434 void Recorder::ContextState::translate(float x, float y)
435 {
436     ctm.translate(x, y);
437     clipBounds.move(-x, -y);
438 }
439
440 void Recorder::ContextState::rotate(float angleInRadians)
441 {
442     double angleInDegrees = rad2deg(static_cast<double>(angleInRadians));
443     ctm.rotate(angleInDegrees);
444     
445     AffineTransform rotation;
446     rotation.rotate(angleInDegrees);
447
448     if (Optional<AffineTransform> inverse = rotation.inverse())
449         clipBounds = inverse.value().mapRect(clipBounds);
450 }
451
452 void Recorder::ContextState::scale(const FloatSize& size)
453 {
454     ctm.scale(size);
455     clipBounds.scale(1 / size.width(), 1 / size.height());
456 }
457
458 void Recorder::ContextState::concatCTM(const AffineTransform& matrix)
459 {
460     ctm *= matrix;
461
462     if (Optional<AffineTransform> inverse = matrix.inverse())
463         clipBounds = inverse.value().mapRect(clipBounds);
464 }
465
466 } // namespace DisplayList
467 } // namespace WebCore