1/*
2 * Copyright (C) 2015 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 "DisplayListItems.h"
28
29#include "FontCascade.h"
30#include <wtf/text/TextStream.h>
31
32namespace WebCore {
33namespace DisplayList {
34
35// Should match RenderTheme::platformFocusRingWidth()
36static const float platformFocusRingWidth = 3;
37
38#if !defined(NDEBUG) || !LOG_DISABLED
39WTF::CString Item::description() const
40{
41 TextStream ts;
42 ts << *this;
43 return ts.release().utf8();
44}
45#endif
46
47size_t Item::sizeInBytes(const Item& item)
48{
49 switch (item.type()) {
50 case ItemType::Save:
51 return sizeof(downcast<Save>(item));
52 case ItemType::Restore:
53 return sizeof(downcast<Restore>(item));
54 case ItemType::Translate:
55 return sizeof(downcast<Translate>(item));
56 case ItemType::Rotate:
57 return sizeof(downcast<Rotate>(item));
58 case ItemType::Scale:
59 return sizeof(downcast<Scale>(item));
60 case ItemType::ConcatenateCTM:
61 return sizeof(downcast<ConcatenateCTM>(item));
62 case ItemType::SetState:
63 return sizeof(downcast<SetState>(item));
64 case ItemType::SetLineCap:
65 return sizeof(downcast<SetLineCap>(item));
66 case ItemType::SetLineDash:
67 return sizeof(downcast<SetLineDash>(item));
68 case ItemType::SetLineJoin:
69 return sizeof(downcast<SetLineJoin>(item));
70 case ItemType::SetMiterLimit:
71 return sizeof(downcast<SetMiterLimit>(item));
72 case ItemType::ClearShadow:
73 return sizeof(downcast<ClearShadow>(item));
74 case ItemType::Clip:
75 return sizeof(downcast<Clip>(item));
76 case ItemType::ClipOut:
77 return sizeof(downcast<ClipOut>(item));
78 case ItemType::ClipOutToPath:
79 return sizeof(downcast<ClipOutToPath>(item));
80 case ItemType::ClipPath:
81 return sizeof(downcast<ClipPath>(item));
82 case ItemType::DrawGlyphs:
83 return sizeof(downcast<DrawGlyphs>(item));
84 case ItemType::DrawImage:
85 return sizeof(downcast<DrawImage>(item));
86 case ItemType::DrawTiledImage:
87 return sizeof(downcast<DrawTiledImage>(item));
88 case ItemType::DrawTiledScaledImage:
89 return sizeof(downcast<DrawTiledScaledImage>(item));
90#if USE(CG) || USE(CAIRO)
91 case ItemType::DrawNativeImage:
92 return sizeof(downcast<DrawNativeImage>(item));
93#endif
94 case ItemType::DrawPattern:
95 return sizeof(downcast<DrawPattern>(item));
96 case ItemType::DrawRect:
97 return sizeof(downcast<DrawRect>(item));
98 case ItemType::DrawLine:
99 return sizeof(downcast<DrawLine>(item));
100 case ItemType::DrawLinesForText:
101 return sizeof(downcast<DrawLinesForText>(item));
102 case ItemType::DrawDotsForDocumentMarker:
103 return sizeof(downcast<DrawDotsForDocumentMarker>(item));
104 case ItemType::DrawEllipse:
105 return sizeof(downcast<DrawEllipse>(item));
106 case ItemType::DrawPath:
107 return sizeof(downcast<DrawPath>(item));
108 case ItemType::DrawFocusRingPath:
109 return sizeof(downcast<DrawFocusRingPath>(item));
110 case ItemType::DrawFocusRingRects:
111 return sizeof(downcast<DrawFocusRingRects>(item));
112 case ItemType::FillRect:
113 return sizeof(downcast<FillRect>(item));
114 case ItemType::FillRectWithColor:
115 return sizeof(downcast<FillRectWithColor>(item));
116 case ItemType::FillRectWithGradient:
117 return sizeof(downcast<FillRectWithGradient>(item));
118 case ItemType::FillCompositedRect:
119 return sizeof(downcast<FillCompositedRect>(item));
120 case ItemType::FillRoundedRect:
121 return sizeof(downcast<FillRoundedRect>(item));
122 case ItemType::FillRectWithRoundedHole:
123 return sizeof(downcast<FillRectWithRoundedHole>(item));
124 case ItemType::FillPath:
125 return sizeof(downcast<FillPath>(item));
126 case ItemType::FillEllipse:
127 return sizeof(downcast<FillEllipse>(item));
128 case ItemType::StrokeRect:
129 return sizeof(downcast<StrokeRect>(item));
130 case ItemType::StrokePath:
131 return sizeof(downcast<StrokePath>(item));
132 case ItemType::StrokeEllipse:
133 return sizeof(downcast<StrokeEllipse>(item));
134 case ItemType::ClearRect:
135 return sizeof(downcast<ClearRect>(item));
136 case ItemType::BeginTransparencyLayer:
137 return sizeof(downcast<BeginTransparencyLayer>(item));
138 case ItemType::EndTransparencyLayer:
139 return sizeof(downcast<EndTransparencyLayer>(item));
140#if USE(CG)
141 case ItemType::ApplyStrokePattern:
142 return sizeof(downcast<ApplyStrokePattern>(item));
143 case ItemType::ApplyFillPattern:
144 return sizeof(downcast<ApplyFillPattern>(item));
145#endif
146 case ItemType::ApplyDeviceScaleFactor:
147 return sizeof(downcast<ApplyDeviceScaleFactor>(item));
148 }
149 return 0;
150}
151
152static TextStream& operator<<(TextStream& ts, const DrawingItem& item)
153{
154 ts.startGroup();
155 ts << "extent ";
156 if (item.extentKnown())
157 ts << item.extent();
158 else
159 ts << "unknown";
160
161 ts.endGroup();
162 return ts;
163}
164
165void Save::apply(GraphicsContext& context) const
166{
167 context.save();
168}
169
170static TextStream& operator<<(TextStream& ts, const Save& item)
171{
172 ts.dumpProperty("restore-index", item.restoreIndex());
173 return ts;
174}
175
176void Restore::apply(GraphicsContext& context) const
177{
178 context.restore();
179}
180
181void Translate::apply(GraphicsContext& context) const
182{
183 context.translate(m_x, m_y);
184}
185
186static TextStream& operator<<(TextStream& ts, const Translate& item)
187{
188 ts.dumpProperty("x", item.x());
189 ts.dumpProperty("y", item.y());
190
191 return ts;
192}
193
194void Rotate::apply(GraphicsContext& context) const
195{
196 context.rotate(m_angle);
197}
198
199static TextStream& operator<<(TextStream& ts, const Rotate& item)
200{
201 ts.dumpProperty("angle", item.angle());
202
203 return ts;
204}
205
206void Scale::apply(GraphicsContext& context) const
207{
208 context.scale(m_size);
209}
210
211static TextStream& operator<<(TextStream& ts, const Scale& item)
212{
213 ts.dumpProperty("size", item.amount());
214
215 return ts;
216}
217
218ConcatenateCTM::ConcatenateCTM(const AffineTransform& transform)
219 : Item(ItemType::ConcatenateCTM)
220 , m_transform(transform)
221{
222}
223
224void ConcatenateCTM::apply(GraphicsContext& context) const
225{
226 context.concatCTM(m_transform);
227}
228
229static TextStream& operator<<(TextStream& ts, const ConcatenateCTM& item)
230{
231 ts.dumpProperty("ctm", item.transform());
232
233 return ts;
234}
235
236void SetState::apply(GraphicsContext& context) const
237{
238 m_state.apply(context);
239}
240
241void SetState::accumulate(const GraphicsContextState& state, GraphicsContextState::StateChangeFlags flags)
242{
243 m_state.accumulate(state, flags);
244}
245
246static TextStream& operator<<(TextStream& ts, const SetState& state)
247{
248 ts << state.state();
249 return ts;
250}
251
252void SetLineCap::apply(GraphicsContext& context) const
253{
254 context.setLineCap(m_lineCap);
255}
256
257static TextStream& operator<<(TextStream& ts, const SetLineCap& lineCap)
258{
259 ts.dumpProperty("line-cap", lineCap.lineCap());
260 return ts;
261}
262
263void SetLineDash::apply(GraphicsContext& context) const
264{
265 context.setLineDash(m_dashArray, m_dashOffset);
266}
267
268static TextStream& operator<<(TextStream& ts, const SetLineDash& lineDash)
269{
270 ts.dumpProperty("dash-array", lineDash.dashArray());
271 ts.dumpProperty("dash-offset", lineDash.dashOffset());
272 return ts;
273}
274
275void SetLineJoin::apply(GraphicsContext& context) const
276{
277 context.setLineJoin(m_lineJoin);
278}
279
280static TextStream& operator<<(TextStream& ts, const SetLineJoin& lineJoin)
281{
282 ts.dumpProperty("line-join", lineJoin.lineJoin());
283 return ts;
284}
285
286void SetMiterLimit::apply(GraphicsContext& context) const
287{
288 context.setMiterLimit(m_miterLimit);
289}
290
291static TextStream& operator<<(TextStream& ts, const SetMiterLimit& miterLimit)
292{
293 ts.dumpProperty("mitre-limit", miterLimit.miterLimit());
294 return ts;
295}
296
297void ClearShadow::apply(GraphicsContext& context) const
298{
299 context.clearShadow();
300}
301
302void Clip::apply(GraphicsContext& context) const
303{
304 context.clip(m_rect);
305}
306
307static TextStream& operator<<(TextStream& ts, const Clip& item)
308{
309 ts.dumpProperty("rect", item.rect());
310 return ts;
311}
312
313void ClipOut::apply(GraphicsContext& context) const
314{
315 context.clipOut(m_rect);
316}
317
318static TextStream& operator<<(TextStream& ts, const ClipOut& item)
319{
320 ts.dumpProperty("rect", item.rect());
321 return ts;
322}
323
324void ClipOutToPath::apply(GraphicsContext& context) const
325{
326 context.clipOut(m_path);
327}
328
329static TextStream& operator<<(TextStream& ts, const ClipOutToPath& item)
330{
331 ts.dumpProperty("path", item.path());
332 return ts;
333}
334
335void ClipPath::apply(GraphicsContext& context) const
336{
337 context.clipPath(m_path, m_windRule);
338}
339
340static TextStream& operator<<(TextStream& ts, const ClipPath& item)
341{
342 ts.dumpProperty("path", item.path());
343 ts.dumpProperty("wind-rule", item.windRule());
344 return ts;
345}
346
347DrawGlyphs::DrawGlyphs(const Font& font, const GlyphBufferGlyph* glyphs, const GlyphBufferAdvance* advances, unsigned count, const FloatPoint& blockLocation, const FloatSize& localAnchor, FontSmoothingMode smoothingMode)
348 : DrawingItem(ItemType::DrawGlyphs)
349 , m_font(const_cast<Font&>(font))
350 , m_blockLocation(blockLocation)
351 , m_localAnchor(localAnchor)
352 , m_smoothingMode(smoothingMode)
353{
354 m_glyphs.reserveInitialCapacity(count);
355 m_advances.reserveInitialCapacity(count);
356 for (unsigned i = 0; i < count; ++i) {
357 m_glyphs.uncheckedAppend(glyphs[i]);
358 m_advances.uncheckedAppend(advances[i]);
359 }
360 computeBounds();
361}
362
363inline GlyphBuffer DrawGlyphs::generateGlyphBuffer() const
364{
365 GlyphBuffer result;
366 for (size_t i = 0; i < m_glyphs.size(); ++i) {
367 result.add(m_glyphs[i], &m_font.get(), m_advances[i], GlyphBuffer::noOffset);
368 }
369 return result;
370}
371
372void DrawGlyphs::apply(GraphicsContext& context) const
373{
374 context.drawGlyphs(m_font, generateGlyphBuffer(), 0, m_glyphs.size(), anchorPoint(), m_smoothingMode);
375}
376
377void DrawGlyphs::computeBounds()
378{
379 // FIXME: This code doesn't actually take the extents of the glyphs into consideration. It assumes that
380 // the glyph lies entirely within its [(ascent + descent), advance] rect.
381 float ascent = m_font->fontMetrics().floatAscent();
382 float descent = m_font->fontMetrics().floatDescent();
383 FloatPoint current = toFloatPoint(localAnchor());
384 size_t numGlyphs = m_glyphs.size();
385 for (size_t i = 0; i < numGlyphs; ++i) {
386 GlyphBufferAdvance advance = m_advances[i];
387 FloatRect glyphRect = FloatRect(current.x(), current.y() - ascent, advance.width(), ascent + descent);
388 m_bounds.unite(glyphRect);
389
390 current.move(advance.width(), advance.height());
391 }
392}
393
394Optional<FloatRect> DrawGlyphs::localBounds(const GraphicsContext&) const
395{
396 FloatRect localBounds = m_bounds;
397 localBounds.move(m_blockLocation.x(), m_blockLocation.y());
398 return localBounds;
399}
400
401static TextStream& operator<<(TextStream& ts, const DrawGlyphs& item)
402{
403 ts << static_cast<const DrawingItem&>(item);
404 // FIXME: dump more stuff.
405 ts.dumpProperty("block-location", item.blockLocation());
406 ts.dumpProperty("local-anchor", item.localAnchor());
407 ts.dumpProperty("anchor-point", item.anchorPoint());
408 ts.dumpProperty("length", item.glyphs().size());
409
410 return ts;
411}
412
413DrawImage::DrawImage(Image& image, const FloatRect& destination, const FloatRect& source, const ImagePaintingOptions& imagePaintingOptions)
414 : DrawingItem(ItemType::DrawImage)
415 , m_image(image)
416 , m_destination(destination)
417 , m_source(source)
418 , m_imagePaintingOptions(imagePaintingOptions)
419{
420}
421
422void DrawImage::apply(GraphicsContext& context) const
423{
424 context.drawImage(m_image.get(), m_destination, m_source, m_imagePaintingOptions);
425}
426
427static TextStream& operator<<(TextStream& ts, const DrawImage& item)
428{
429 ts << static_cast<const DrawingItem&>(item);
430 ts.dumpProperty("image", item.image());
431 ts.dumpProperty("source-rect", item.source());
432 ts.dumpProperty("dest-rect", item.destination());
433 return ts;
434}
435
436DrawTiledImage::DrawTiledImage(Image& image, const FloatRect& destination, const FloatPoint& source, const FloatSize& tileSize, const FloatSize& spacing, const ImagePaintingOptions& imagePaintingOptions)
437 : DrawingItem(ItemType::DrawTiledImage)
438 , m_image(image)
439 , m_destination(destination)
440 , m_source(source)
441 , m_tileSize(tileSize)
442 , m_spacing(spacing)
443 , m_imagePaintingOptions(imagePaintingOptions)
444{
445}
446
447void DrawTiledImage::apply(GraphicsContext& context) const
448{
449 context.drawTiledImage(m_image.get(), m_destination, m_source, m_tileSize, m_spacing, m_imagePaintingOptions);
450}
451
452static TextStream& operator<<(TextStream& ts, const DrawTiledImage& item)
453{
454 ts << static_cast<const DrawingItem&>(item);
455 ts.dumpProperty("image", item.image());
456 ts.dumpProperty("source-point", item.source());
457 ts.dumpProperty("dest-rect", item.destination());
458 ts.dumpProperty("tile-size", item.tileSize());
459 ts.dumpProperty("spacing", item.spacing());
460 return ts;
461}
462
463DrawTiledScaledImage::DrawTiledScaledImage(Image& image, const FloatRect& destination, const FloatRect& source, const FloatSize& tileScaleFactor, Image::TileRule hRule, Image::TileRule vRule, const ImagePaintingOptions& imagePaintingOptions)
464 : DrawingItem(ItemType::DrawTiledScaledImage)
465 , m_image(image)
466 , m_destination(destination)
467 , m_source(source)
468 , m_tileScaleFactor(tileScaleFactor)
469 , m_hRule(hRule)
470 , m_vRule(vRule)
471 , m_imagePaintingOptions(imagePaintingOptions)
472{
473}
474
475void DrawTiledScaledImage::apply(GraphicsContext& context) const
476{
477 context.drawTiledImage(m_image.get(), m_destination, m_source, m_tileScaleFactor, m_hRule, m_vRule, m_imagePaintingOptions);
478}
479
480static TextStream& operator<<(TextStream& ts, const DrawTiledScaledImage& item)
481{
482 ts << static_cast<const DrawingItem&>(item);
483 ts.dumpProperty("image", item.image());
484 ts.dumpProperty("source-rect", item.source());
485 ts.dumpProperty("dest-rect", item.destination());
486 return ts;
487}
488
489#if USE(CG) || USE(CAIRO)
490DrawNativeImage::DrawNativeImage(const NativeImagePtr& image, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, ImageOrientation orientation)
491 : DrawingItem(ItemType::DrawNativeImage)
492#if USE(CG)
493 // FIXME: Need to store an image for Cairo.
494 , m_image(image)
495#endif
496 , m_imageSize(imageSize)
497 , m_destination(destRect)
498 , m_srcRect(srcRect)
499#if USE(CG)
500 , m_op(op)
501 , m_blendMode(blendMode)
502#endif
503 , m_orientation(orientation)
504{
505#if !USE(CG)
506 UNUSED_PARAM(image);
507 UNUSED_PARAM(op);
508 UNUSED_PARAM(blendMode);
509#endif
510}
511
512void DrawNativeImage::apply(GraphicsContext& context) const
513{
514#if USE(CG)
515 context.drawNativeImage(m_image, m_imageSize, m_destination, m_srcRect, m_op, m_blendMode, m_orientation);
516#else
517 UNUSED_PARAM(context);
518#endif
519}
520
521static TextStream& operator<<(TextStream& ts, const DrawNativeImage& item)
522{
523 ts << static_cast<const DrawingItem&>(item);
524 // FIXME: dump more stuff.
525 ts.dumpProperty("source-rect", item.source());
526 ts.dumpProperty("dest-rect", item.destination());
527 return ts;
528}
529#endif
530
531DrawPattern::DrawPattern(Image& image, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, BlendMode blendMode)
532 : DrawingItem(ItemType::DrawPattern)
533 , m_image(image)
534 , m_patternTransform(patternTransform)
535 , m_tileRect(tileRect)
536 , m_destination(destRect)
537 , m_phase(phase)
538 , m_spacing(spacing)
539 , m_op(op)
540 , m_blendMode(blendMode)
541{
542}
543
544void DrawPattern::apply(GraphicsContext& context) const
545{
546 context.drawPattern(m_image.get(), m_destination, m_tileRect, m_patternTransform, m_phase, m_spacing, m_op, m_blendMode);
547}
548
549static TextStream& operator<<(TextStream& ts, const DrawPattern& item)
550{
551 ts << static_cast<const DrawingItem&>(item);
552 ts.dumpProperty("image", item.image());
553 ts.dumpProperty("pattern-transform", item.patternTransform());
554 ts.dumpProperty("tile-rect", item.tileRect());
555 ts.dumpProperty("dest-rect", item.destRect());
556 ts.dumpProperty("phase", item.phase());
557 ts.dumpProperty("spacing", item.spacing());
558 return ts;
559}
560
561void DrawRect::apply(GraphicsContext& context) const
562{
563 context.drawRect(m_rect, m_borderThickness);
564}
565
566static TextStream& operator<<(TextStream& ts, const DrawRect& item)
567{
568 ts << static_cast<const DrawingItem&>(item);
569 ts.dumpProperty("rect", item.rect());
570 ts.dumpProperty("border-thickness", item.borderThickness());
571 return ts;
572}
573
574Optional<FloatRect> DrawLine::localBounds(const GraphicsContext&) const
575{
576 FloatRect bounds;
577 bounds.fitToPoints(m_point1, m_point2);
578 return bounds;
579}
580
581void DrawLine::apply(GraphicsContext& context) const
582{
583 context.drawLine(m_point1, m_point2);
584}
585
586static TextStream& operator<<(TextStream& ts, const DrawLine& item)
587{
588 ts << static_cast<const DrawingItem&>(item);
589 ts.dumpProperty("point-1", item.point1());
590 ts.dumpProperty("point-2", item.point2());
591 return ts;
592}
593
594void DrawLinesForText::apply(GraphicsContext& context) const
595{
596 context.drawLinesForText(point(), m_thickness, m_widths, m_printing, m_doubleLines);
597}
598
599Optional<FloatRect> DrawLinesForText::localBounds(const GraphicsContext&) const
600{
601 // This function needs to return a value equal to or enclosing what GraphicsContext::computeLineBoundsAndAntialiasingModeForText() returns.
602
603 if (!m_widths.size())
604 return FloatRect();
605
606 FloatRect result(point(), FloatSize(m_widths.last(), m_thickness));
607 result.inflate(1); // Account for pixel snapping. FIXME: This isn't perfect, as it doesn't take the CTM into account.
608 return result;
609}
610
611static TextStream& operator<<(TextStream& ts, const DrawLinesForText& item)
612{
613 ts << static_cast<const DrawingItem&>(item);
614 ts.dumpProperty("block-location", item.blockLocation());
615 ts.dumpProperty("local-anchor", item.localAnchor());
616 ts.dumpProperty("point", item.point());
617 ts.dumpProperty("thickness", item.thickness());
618 ts.dumpProperty("double", item.doubleLines());
619 ts.dumpProperty("widths", item.widths());
620 ts.dumpProperty("is-printing", item.isPrinting());
621 ts.dumpProperty("double", item.doubleLines());
622 return ts;
623}
624
625void DrawDotsForDocumentMarker::apply(GraphicsContext& context) const
626{
627 context.drawDotsForDocumentMarker(m_rect, m_style);
628}
629
630Optional<FloatRect> DrawDotsForDocumentMarker::localBounds(const GraphicsContext&) const
631{
632 return m_rect;
633}
634
635static TextStream& operator<<(TextStream& ts, const DrawDotsForDocumentMarker& item)
636{
637 ts << static_cast<const DrawingItem&>(item);
638 ts.dumpProperty("rect", item.rect());
639 return ts;
640}
641
642void DrawEllipse::apply(GraphicsContext& context) const
643{
644 context.drawEllipse(m_rect);
645}
646
647static TextStream& operator<<(TextStream& ts, const DrawEllipse& item)
648{
649 ts.dumpProperty("rect", item.rect());
650 return ts;
651}
652
653void DrawPath::apply(GraphicsContext& context) const
654{
655#if USE(CG)
656 context.drawPath(m_path);
657#else
658 UNUSED_PARAM(context);
659#endif
660}
661
662static TextStream& operator<<(TextStream& ts, const DrawPath& item)
663{
664 ts << static_cast<const DrawingItem&>(item);
665// ts.dumpProperty("path", item.path()); // FIXME: add logging for paths.
666 return ts;
667}
668
669void DrawFocusRingPath::apply(GraphicsContext& context) const
670{
671 context.drawFocusRing(m_path, m_width, m_offset, m_color);
672}
673
674Optional<FloatRect> DrawFocusRingPath::localBounds(const GraphicsContext&) const
675{
676 FloatRect result = m_path.fastBoundingRect();
677 result.inflate(platformFocusRingWidth);
678 return result;
679}
680
681static TextStream& operator<<(TextStream& ts, const DrawFocusRingPath& item)
682{
683 ts << static_cast<const DrawingItem&>(item);
684// ts.dumpProperty("path", item.path()); // FIXME: add logging for paths.
685 ts.dumpProperty("width", item.width());
686 ts.dumpProperty("offset", item.offset());
687 ts.dumpProperty("color", item.color());
688 return ts;
689}
690
691void DrawFocusRingRects::apply(GraphicsContext& context) const
692{
693 context.drawFocusRing(m_rects, m_width, m_offset, m_color);
694}
695
696Optional<FloatRect> DrawFocusRingRects::localBounds(const GraphicsContext&) const
697{
698 FloatRect result;
699 for (auto& rect : m_rects)
700 result.unite(rect);
701 result.inflate(platformFocusRingWidth);
702 return result;
703}
704
705static TextStream& operator<<(TextStream& ts, const DrawFocusRingRects& item)
706{
707 ts << static_cast<const DrawingItem&>(item);
708 ts.dumpProperty("rects", item.rects());
709 ts.dumpProperty("width", item.width());
710 ts.dumpProperty("offset", item.offset());
711 ts.dumpProperty("color", item.color());
712 return ts;
713}
714
715void FillRect::apply(GraphicsContext& context) const
716{
717 context.fillRect(m_rect);
718}
719
720static TextStream& operator<<(TextStream& ts, const FillRect& item)
721{
722 ts << static_cast<const DrawingItem&>(item);
723 ts.dumpProperty("rect", item.rect());
724 return ts;
725}
726
727void FillRectWithColor::apply(GraphicsContext& context) const
728{
729 context.fillRect(m_rect, m_color);
730}
731
732static TextStream& operator<<(TextStream& ts, const FillRectWithColor& item)
733{
734 ts << static_cast<const DrawingItem&>(item);
735 ts.dumpProperty("rect", item.rect());
736 ts.dumpProperty("color", item.color());
737 return ts;
738}
739
740void FillRectWithGradient::apply(GraphicsContext& context) const
741{
742 context.fillRect(m_rect, m_gradient.get());
743}
744
745static TextStream& operator<<(TextStream& ts, const FillRectWithGradient& item)
746{
747 ts << static_cast<const DrawingItem&>(item);
748 // FIXME: log gradient.
749 ts.dumpProperty("rect", item.rect());
750 return ts;
751}
752
753void FillCompositedRect::apply(GraphicsContext& context) const
754{
755 context.fillRect(m_rect, m_color, m_op, m_blendMode);
756}
757
758static TextStream& operator<<(TextStream& ts, const FillCompositedRect& item)
759{
760 ts << static_cast<const DrawingItem&>(item);
761 ts.dumpProperty("rect", item.rect());
762 ts.dumpProperty("color", item.color());
763 ts.dumpProperty("composite-operation", item.compositeOperator());
764 ts.dumpProperty("blend-mode", item.blendMode());
765 return ts;
766}
767
768void FillRoundedRect::apply(GraphicsContext& context) const
769{
770 context.fillRoundedRect(m_rect, m_color, m_blendMode);
771}
772
773static TextStream& operator<<(TextStream& ts, const FillRoundedRect& item)
774{
775 ts << static_cast<const DrawingItem&>(item);
776 ts.dumpProperty("rect", item.roundedRect());
777 ts.dumpProperty("color", item.color());
778 ts.dumpProperty("blend-mode", item.blendMode());
779 return ts;
780}
781
782void FillRectWithRoundedHole::apply(GraphicsContext& context) const
783{
784 context.fillRectWithRoundedHole(m_rect, m_roundedHoleRect, m_color);
785}
786
787static TextStream& operator<<(TextStream& ts, const FillRectWithRoundedHole& item)
788{
789 ts << static_cast<const DrawingItem&>(item);
790 ts.dumpProperty("rect", item.rect());
791 ts.dumpProperty("rounded-hole-rect", item.roundedHoleRect());
792 ts.dumpProperty("color", item.color());
793 return ts;
794}
795
796void FillPath::apply(GraphicsContext& context) const
797{
798 context.fillPath(m_path);
799}
800
801static TextStream& operator<<(TextStream& ts, const FillPath& item)
802{
803 ts << static_cast<const DrawingItem&>(item);
804 ts.dumpProperty("path", item.path());
805 return ts;
806}
807
808void FillEllipse::apply(GraphicsContext& context) const
809{
810 context.fillEllipse(m_rect);
811}
812
813static TextStream& operator<<(TextStream& ts, const FillEllipse& item)
814{
815 ts << static_cast<const DrawingItem&>(item);
816 ts.dumpProperty("rect", item.rect());
817 return ts;
818}
819
820Optional<FloatRect> StrokeRect::localBounds(const GraphicsContext&) const
821{
822 FloatRect bounds = m_rect;
823 bounds.expand(m_lineWidth, m_lineWidth);
824 return bounds;
825}
826
827void StrokeRect::apply(GraphicsContext& context) const
828{
829 context.strokeRect(m_rect, m_lineWidth);
830}
831
832static TextStream& operator<<(TextStream& ts, const StrokeRect& item)
833{
834 ts << static_cast<const DrawingItem&>(item);
835 ts.dumpProperty("rect", item.rect());
836 ts.dumpProperty("line-width", item.lineWidth());
837 return ts;
838}
839
840Optional<FloatRect> StrokePath::localBounds(const GraphicsContext& context) const
841{
842 // FIXME: Need to take stroke thickness into account correctly, via CGPathByStrokingPath().
843 float strokeThickness = context.strokeThickness();
844
845 FloatRect bounds = m_path.boundingRect();
846 bounds.expand(strokeThickness, strokeThickness);
847 return bounds;
848}
849
850void StrokePath::apply(GraphicsContext& context) const
851{
852 context.strokePath(m_path);
853}
854
855static TextStream& operator<<(TextStream& ts, const StrokePath& item)
856{
857 ts << static_cast<const DrawingItem&>(item);
858 ts.dumpProperty("path", item.path());
859 return ts;
860}
861
862Optional<FloatRect> StrokeEllipse::localBounds(const GraphicsContext& context) const
863{
864 float strokeThickness = context.strokeThickness();
865
866 FloatRect bounds = m_rect;
867 bounds.expand(strokeThickness, strokeThickness);
868 return bounds;
869}
870
871void StrokeEllipse::apply(GraphicsContext& context) const
872{
873 context.strokeEllipse(m_rect);
874}
875
876static TextStream& operator<<(TextStream& ts, const StrokeEllipse& item)
877{
878 ts << static_cast<const DrawingItem&>(item);
879 ts.dumpProperty("rect", item.rect());
880 return ts;
881}
882
883void ClearRect::apply(GraphicsContext& context) const
884{
885 context.clearRect(m_rect);
886}
887
888static TextStream& operator<<(TextStream& ts, const ClearRect& item)
889{
890 ts << static_cast<const DrawingItem&>(item);
891 ts.dumpProperty("rect", item.rect());
892 return ts;
893}
894
895void BeginTransparencyLayer::apply(GraphicsContext& context) const
896{
897 context.beginTransparencyLayer(m_opacity);
898}
899
900static TextStream& operator<<(TextStream& ts, const BeginTransparencyLayer& item)
901{
902 ts << static_cast<const DrawingItem&>(item);
903 ts.dumpProperty("opacity", item.opacity());
904 return ts;
905}
906
907void EndTransparencyLayer::apply(GraphicsContext& context) const
908{
909 context.endTransparencyLayer();
910}
911
912#if USE(CG)
913void ApplyStrokePattern::apply(GraphicsContext& context) const
914{
915 context.applyStrokePattern();
916}
917
918void ApplyFillPattern::apply(GraphicsContext& context) const
919{
920 context.applyFillPattern();
921}
922#endif
923
924void ApplyDeviceScaleFactor::apply(GraphicsContext& context) const
925{
926 context.applyDeviceScaleFactor(m_scaleFactor);
927}
928
929static TextStream& operator<<(TextStream& ts, const ApplyDeviceScaleFactor& item)
930{
931 ts.dumpProperty("scale-factor", item.scaleFactor());
932 return ts;
933}
934
935static TextStream& operator<<(TextStream& ts, const ItemType& type)
936{
937 switch (type) {
938 case ItemType::Save: ts << "save"; break;
939 case ItemType::Restore: ts << "restore"; break;
940 case ItemType::Translate: ts << "translate"; break;
941 case ItemType::Rotate: ts << "rotate"; break;
942 case ItemType::Scale: ts << "scale"; break;
943 case ItemType::ConcatenateCTM: ts << "concatentate-ctm"; break;
944 case ItemType::SetState: ts << "set-state"; break;
945 case ItemType::SetLineCap: ts << "set-line-cap"; break;
946 case ItemType::SetLineDash: ts << "set-line-dash"; break;
947 case ItemType::SetLineJoin: ts << "set-line-join"; break;
948 case ItemType::SetMiterLimit: ts << "set-miter-limit"; break;
949 case ItemType::Clip: ts << "clip"; break;
950 case ItemType::ClipOut: ts << "clip-out"; break;
951 case ItemType::ClipOutToPath: ts << "clip-out-to-path"; break;
952 case ItemType::ClipPath: ts << "clip-path"; break;
953 case ItemType::DrawGlyphs: ts << "draw-glyphs"; break;
954 case ItemType::DrawImage: ts << "draw-image"; break;
955 case ItemType::DrawTiledImage: ts << "draw-tiled-image"; break;
956 case ItemType::DrawTiledScaledImage: ts << "draw-tiled-scaled-image"; break;
957#if USE(CG) || USE(CAIRO)
958 case ItemType::DrawNativeImage: ts << "draw-native-image"; break;
959#endif
960 case ItemType::DrawPattern: ts << "draw-pattern"; break;
961 case ItemType::DrawRect: ts << "draw-rect"; break;
962 case ItemType::DrawLine: ts << "draw-line"; break;
963 case ItemType::DrawLinesForText: ts << "draw-lines-for-text"; break;
964 case ItemType::DrawDotsForDocumentMarker: ts << "draw-dots-for-document-marker"; break;
965 case ItemType::DrawEllipse: ts << "draw-ellipse"; break;
966 case ItemType::DrawPath: ts << "draw-path"; break;
967 case ItemType::DrawFocusRingPath: ts << "draw-focus-ring-path"; break;
968 case ItemType::DrawFocusRingRects: ts << "draw-focus-ring-rects"; break;
969 case ItemType::FillRect: ts << "fill-rect"; break;
970 case ItemType::FillRectWithColor: ts << "fill-rect-with-color"; break;
971 case ItemType::FillRectWithGradient: ts << "fill-rect-with-gradient"; break;
972 case ItemType::FillCompositedRect: ts << "fill-composited-rect"; break;
973 case ItemType::FillRoundedRect: ts << "fill-rounded-rect"; break;
974 case ItemType::FillRectWithRoundedHole: ts << "fill-rect-with-rounded-hole"; break;
975 case ItemType::FillPath: ts << "fill-path"; break;
976 case ItemType::FillEllipse: ts << "fill-ellipse"; break;
977 case ItemType::StrokeRect: ts << "stroke-rect"; break;
978 case ItemType::StrokePath: ts << "stroke-path"; break;
979 case ItemType::StrokeEllipse: ts << "stroke-ellipse"; break;
980 case ItemType::ClearRect: ts << "clear-rect"; break;
981 case ItemType::BeginTransparencyLayer: ts << "begin-transparency-layer"; break;
982 case ItemType::EndTransparencyLayer: ts << "end-transparency-layer"; break;
983#if USE(CG)
984 case ItemType::ApplyStrokePattern: ts << "apply-stroke-pattern"; break;
985 case ItemType::ApplyFillPattern: ts << "apply-fill-pattern"; break;
986#endif
987 case ItemType::ApplyDeviceScaleFactor: ts << "apply-device-scale-factor"; break;
988 case ItemType::ClearShadow: ts << "clear-shadow"; break;
989 }
990 return ts;
991}
992
993TextStream& operator<<(TextStream& ts, const Item& item)
994{
995 TextStream::GroupScope group(ts);
996 ts << item.type();
997
998 // FIXME: Make a macro which takes a macro for all these enumeration switches
999 switch (item.type()) {
1000 case ItemType::Save:
1001 ts << downcast<Save>(item);
1002 break;
1003 case ItemType::Translate:
1004 ts << downcast<Translate>(item);
1005 break;
1006 case ItemType::Rotate:
1007 ts << downcast<Rotate>(item);
1008 break;
1009 case ItemType::Scale:
1010 ts << downcast<Scale>(item);
1011 break;
1012 case ItemType::ConcatenateCTM:
1013 ts << downcast<ConcatenateCTM>(item);
1014 break;
1015 case ItemType::SetState:
1016 ts << downcast<SetState>(item);
1017 break;
1018 case ItemType::SetLineCap:
1019 ts << downcast<SetLineCap>(item);
1020 break;
1021 case ItemType::SetLineDash:
1022 ts << downcast<SetLineDash>(item);
1023 break;
1024 case ItemType::SetLineJoin:
1025 ts << downcast<SetLineJoin>(item);
1026 break;
1027 case ItemType::SetMiterLimit:
1028 ts << downcast<SetMiterLimit>(item);
1029 break;
1030 case ItemType::Clip:
1031 ts << downcast<Clip>(item);
1032 break;
1033 case ItemType::ClipOut:
1034 ts << downcast<ClipOut>(item);
1035 break;
1036 case ItemType::ClipOutToPath:
1037 ts << downcast<ClipOutToPath>(item);
1038 break;
1039 case ItemType::ClipPath:
1040 ts << downcast<ClipPath>(item);
1041 break;
1042 case ItemType::DrawGlyphs:
1043 ts << downcast<DrawGlyphs>(item);
1044 break;
1045 case ItemType::DrawImage:
1046 ts << downcast<DrawImage>(item);
1047 break;
1048 case ItemType::DrawTiledImage:
1049 ts << downcast<DrawTiledImage>(item);
1050 break;
1051 case ItemType::DrawTiledScaledImage:
1052 ts << downcast<DrawTiledScaledImage>(item);
1053 break;
1054#if USE(CG) || USE(CAIRO)
1055 case ItemType::DrawNativeImage:
1056 ts << downcast<DrawNativeImage>(item);
1057 break;
1058#endif
1059 case ItemType::DrawPattern:
1060 ts << downcast<DrawPattern>(item);
1061 break;
1062 case ItemType::DrawRect:
1063 ts << downcast<DrawRect>(item);
1064 break;
1065 case ItemType::DrawLine:
1066 ts << downcast<DrawLine>(item);
1067 break;
1068 case ItemType::DrawLinesForText:
1069 ts << downcast<DrawLinesForText>(item);
1070 break;
1071 case ItemType::DrawDotsForDocumentMarker:
1072 ts << downcast<DrawDotsForDocumentMarker>(item);
1073 break;
1074 case ItemType::DrawEllipse:
1075 ts << downcast<DrawEllipse>(item);
1076 break;
1077 case ItemType::DrawPath:
1078 ts << downcast<DrawPath>(item);
1079 break;
1080 case ItemType::DrawFocusRingPath:
1081 ts << downcast<DrawFocusRingPath>(item);
1082 break;
1083 case ItemType::DrawFocusRingRects:
1084 ts << downcast<DrawFocusRingRects>(item);
1085 break;
1086 case ItemType::FillRect:
1087 ts << downcast<FillRect>(item);
1088 break;
1089 case ItemType::FillRectWithColor:
1090 ts << downcast<FillRectWithColor>(item);
1091 break;
1092 case ItemType::FillRectWithGradient:
1093 ts << downcast<FillRectWithGradient>(item);
1094 break;
1095 case ItemType::FillCompositedRect:
1096 ts << downcast<FillCompositedRect>(item);
1097 break;
1098 case ItemType::FillRoundedRect:
1099 ts << downcast<FillRoundedRect>(item);
1100 break;
1101 case ItemType::FillRectWithRoundedHole:
1102 ts << downcast<FillRectWithRoundedHole>(item);
1103 break;
1104 case ItemType::FillPath:
1105 ts << downcast<FillPath>(item);
1106 break;
1107 case ItemType::FillEllipse:
1108 ts << downcast<FillEllipse>(item);
1109 break;
1110 case ItemType::StrokeRect:
1111 ts << downcast<StrokeRect>(item);
1112 break;
1113 case ItemType::StrokePath:
1114 ts << downcast<StrokePath>(item);
1115 break;
1116 case ItemType::StrokeEllipse:
1117 ts << downcast<StrokeEllipse>(item);
1118 break;
1119 case ItemType::ClearRect:
1120 ts << downcast<ClearRect>(item);
1121 break;
1122 case ItemType::BeginTransparencyLayer:
1123 ts << downcast<BeginTransparencyLayer>(item);
1124 break;
1125 case ItemType::ApplyDeviceScaleFactor:
1126 ts << downcast<ApplyDeviceScaleFactor>(item);
1127 break;
1128
1129 // Items with no additional data.
1130 case ItemType::Restore:
1131 case ItemType::EndTransparencyLayer:
1132#if USE(CG)
1133 case ItemType::ApplyStrokePattern:
1134 case ItemType::ApplyFillPattern:
1135#endif
1136 case ItemType::ClearShadow:
1137 break;
1138 }
1139 return ts;
1140}
1141
1142}
1143}
1144