1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/core/paint/inline_box_painter_base.h"
6 
7 #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
8 #include "third_party/blink/renderer/core/paint/box_painter_base.h"
9 #include "third_party/blink/renderer/core/paint/paint_info.h"
10 #include "third_party/blink/renderer/core/paint/paint_layer.h"
11 #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
12 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
13 
14 namespace blink {
15 
PaintBoxDecorationBackground(BoxPainterBase & box_painter,const PaintInfo & paint_info,const PhysicalOffset & paint_offset,const PhysicalRect & adjusted_frame_rect,BackgroundImageGeometry geometry,bool object_has_multiple_boxes,PhysicalBoxSides sides_to_include)16 void InlineBoxPainterBase::PaintBoxDecorationBackground(
17     BoxPainterBase& box_painter,
18     const PaintInfo& paint_info,
19     const PhysicalOffset& paint_offset,
20     const PhysicalRect& adjusted_frame_rect,
21     BackgroundImageGeometry geometry,
22     bool object_has_multiple_boxes,
23     PhysicalBoxSides sides_to_include) {
24   // Shadow comes first and is behind the background and border.
25   PaintNormalBoxShadow(paint_info, line_style_, adjusted_frame_rect);
26 
27   Color background_color =
28       line_style_.VisitedDependentColor(GetCSSPropertyBackgroundColor());
29   PaintFillLayers(box_painter, paint_info, background_color,
30                   line_style_.BackgroundLayers(), adjusted_frame_rect, geometry,
31                   object_has_multiple_boxes);
32 
33   PaintInsetBoxShadow(paint_info, line_style_, adjusted_frame_rect);
34 
35   IntRect adjusted_clip_rect;
36   BorderPaintingType border_painting_type = GetBorderPaintType(
37       adjusted_frame_rect, adjusted_clip_rect, object_has_multiple_boxes);
38   switch (border_painting_type) {
39     case kDontPaintBorders:
40       break;
41     case kPaintBordersWithoutClip:
42       BoxPainterBase::PaintBorder(image_observer_, *document_, node_,
43                                   paint_info, adjusted_frame_rect, line_style_,
44                                   kBackgroundBleedNone, sides_to_include);
45       break;
46     case kPaintBordersWithClip:
47       // FIXME: What the heck do we do with RTL here? The math we're using is
48       // obviously not right, but it isn't even clear how this should work at
49       // all.
50       PhysicalRect image_strip_paint_rect =
51           PaintRectForImageStrip(adjusted_frame_rect, TextDirection::kLtr);
52       GraphicsContextStateSaver state_saver(paint_info.context);
53       paint_info.context.Clip(adjusted_clip_rect);
54       BoxPainterBase::PaintBorder(image_observer_, *document_, node_,
55                                   paint_info, image_strip_paint_rect,
56                                   line_style_);
57       break;
58   }
59 }
60 
PaintFillLayers(BoxPainterBase & box_painter,const PaintInfo & info,const Color & c,const FillLayer & layer,const PhysicalRect & rect,BackgroundImageGeometry & geometry,bool object_has_multiple_boxes)61 void InlineBoxPainterBase::PaintFillLayers(BoxPainterBase& box_painter,
62                                            const PaintInfo& info,
63                                            const Color& c,
64                                            const FillLayer& layer,
65                                            const PhysicalRect& rect,
66                                            BackgroundImageGeometry& geometry,
67                                            bool object_has_multiple_boxes) {
68   // FIXME: This should be a for loop or similar. It's a little non-trivial to
69   // do so, however, since the layers need to be painted in reverse order.
70   if (layer.Next()) {
71     PaintFillLayers(box_painter, info, c, *layer.Next(), rect, geometry,
72                     object_has_multiple_boxes);
73   }
74   PaintFillLayer(box_painter, info, c, layer, rect, geometry,
75                  object_has_multiple_boxes);
76 }
77 
PaintFillLayer(BoxPainterBase & box_painter,const PaintInfo & paint_info,const Color & c,const FillLayer & fill_layer,const PhysicalRect & paint_rect,BackgroundImageGeometry & geometry,bool object_has_multiple_boxes)78 void InlineBoxPainterBase::PaintFillLayer(BoxPainterBase& box_painter,
79                                           const PaintInfo& paint_info,
80                                           const Color& c,
81                                           const FillLayer& fill_layer,
82                                           const PhysicalRect& paint_rect,
83                                           BackgroundImageGeometry& geometry,
84                                           bool object_has_multiple_boxes) {
85   StyleImage* img = fill_layer.GetImage();
86   bool has_fill_image = img && img->CanRender();
87 
88   if (!object_has_multiple_boxes ||
89       (!has_fill_image && !style_.HasBorderRadius())) {
90     box_painter.PaintFillLayer(paint_info, c, fill_layer, paint_rect,
91                                kBackgroundBleedNone, geometry, false);
92     return;
93   }
94 
95   // Handle fill images that clone or spans multiple lines.
96   bool multi_line = object_has_multiple_boxes &&
97                     style_.BoxDecorationBreak() != EBoxDecorationBreak::kClone;
98   PhysicalRect rect =
99       multi_line ? PaintRectForImageStrip(paint_rect, style_.Direction())
100                  : paint_rect;
101   GraphicsContextStateSaver state_saver(paint_info.context);
102   paint_info.context.Clip(PixelSnappedIntRect(paint_rect));
103   box_painter.PaintFillLayer(paint_info, c, fill_layer, rect,
104                              kBackgroundBleedNone, geometry, multi_line,
105                              paint_rect.size);
106 }
107 
108 }  // namespace blink
109