Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: third_party/WebKit/Source/core/paint/NGBoxFragmentPainter.cpp

Issue 2842983002: [LayoutNG] Paint inlines from the fragment tree
Patch Set: Rebase w/HEAD Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "core/paint/NGBoxFragmentPainter.h"
6
7 #include "core/layout/BackgroundBleedAvoidance.h"
8 #include "core/layout/ng/inline/ng_physical_line_box_fragment.h"
9 #include "core/layout/ng/inline/ng_physical_text_fragment.h"
10 #include "core/layout/ng/ng_physical_box_fragment.h"
11 #include "core/paint/BoxBorderPainter.h"
12 #include "core/paint/BoxDecorationData.h"
13 #include "core/paint/NGTextFragmentPainter.h"
14 #include "core/paint/PaintInfo.h"
15 #include "core/paint/PaintLayer.h"
16 #include "core/paint/RoundedInnerRectClipper.h"
17 #include "core/style/FillLayer.h"
18 #include "platform/geometry/LayoutRectOutsets.h"
19 #include "platform/graphics/GraphicsContextStateSaver.h"
20 #include "platform/graphics/paint/DrawingRecorder.h"
21
22 namespace blink {
23
24 void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info,
25 const LayoutPoint& paint_offset) {
26 PaintChildren(paint_info, paint_offset);
27 }
28
29 void NGBoxFragmentPainter::PaintChildren(const PaintInfo& paint_info,
30 const LayoutPoint& paint_offset) {
31 PaintInfo child_info(paint_info);
32 for (const auto& child : box_fragment_->Children()) {
33 if (child->Type() == NGPhysicalBoxFragment::kFragmentLineBox) {
34 const NGPhysicalLineBoxFragment* line_box_fragment =
35 ToNGPhysicalLineBoxFragment(child.Get());
36 PaintLineBox(line_box_fragment, child_info, paint_offset);
37 }
38 }
39 }
40
41 void NGBoxFragmentPainter::PaintLineBox(
42 const NGPhysicalLineBoxFragment* fragment,
43 const PaintInfo& paint_info,
44 const LayoutPoint& paint_offset) {
45 // TODO: Should this check if the line boxes intersects with the dirty rect
46 // like legacy layout or do we want to change the invalidation logic?
47
48 LayoutRect overflow_rect(box_fragment_->VisualOverflowRect());
49 overflow_rect.MoveBy(paint_offset);
50
51 // TODO(eae): Should this go here, in ::Paint or in the NGTextFragmentPainter
52 // class?
53 DrawingRecorder recorder(
54 paint_info.context, *fragment,
55 DisplayItem::PaintPhaseToDrawingType(paint_info.phase),
56 PixelSnappedIntRect(overflow_rect));
57
58 for (const auto& child : fragment->Children()) {
59 if (child->Type() == NGPhysicalBoxFragment::kFragmentLineBox) {
60 CHECK(false);
61 } else if (child->Type() == NGPhysicalBoxFragment::kFragmentText) {
62 const NGPhysicalTextFragment* text_fragment =
63 ToNGPhysicalTextFragment(child.Get());
64 NGTextFragmentPainter(text_fragment)
65 .Paint(GetDocument(), paint_info, paint_offset);
66 }
67 }
68 }
69
70 bool IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
71 const NGPhysicalFragment* fragment,
72 const PaintInfo& paint_info) {
73 // TODO(eae): Implement. Will require changing the type of
74 // PaintInfo::paint_container_ or using the NGBoxFragment container object.
75 return false;
76 }
77
78 void NGBoxFragmentPainter::PaintBoxDecorationBackground(
79 const PaintInfo& paint_info,
80 const LayoutPoint& paint_offset) {
81 LayoutRect paint_rect;
82 if (IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
83 box_fragment_, paint_info)) {
84 // For the case where we are painting the background into the scrolling
85 // contents layer of a composited scroller we need to include the entire
86 // overflow rect.
87
88 // The background painting code assumes that the borders are part of the
89 // paintRect so we expand the paintRect by the border size when painting the
90 // background into the scrolling contents layer.
91 } else {
92 // TODO(eae): We need better converters for ng geometry types. Long term we
93 // probably want to change the paint code to take NGPhysical* but that is a
94 // much bigger change.
95 NGPhysicalSize size = box_fragment_->Size();
96 paint_rect = LayoutRect(LayoutPoint(), LayoutSize(size.width, size.height));
97 }
98
99 paint_rect.MoveBy(paint_offset);
100 PaintBoxDecorationBackgroundWithRect(paint_info, paint_offset, paint_rect);
101 }
102
103 void NGBoxFragmentPainter::PaintBoxDecorationBackgroundWithRect(
104 const PaintInfo& paint_info,
105 const LayoutPoint& paint_offset,
106 const LayoutRect& paint_rect) {
107 bool painting_overflow_contents =
108 IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
109 box_fragment_, paint_info);
110 const ComputedStyle& style = box_fragment_->Style();
111
112 // TODO(eae): Implement support for painting overflow contents.
113 const DisplayItemClient& display_item_client = *box_fragment_;
114 if (DrawingRecorder::UseCachedDrawingIfPossible(
115 paint_info.context, display_item_client,
116 DisplayItem::kBoxDecorationBackground))
117 return;
118
119 DrawingRecorder recorder(
120 paint_info.context, display_item_client,
121 DisplayItem::kBoxDecorationBackground,
122 FloatRect(BoundsForDrawingRecorder(paint_info, paint_offset)));
123 BoxDecorationData box_decoration_data(box_fragment_);
124 GraphicsContextStateSaver state_saver(paint_info.context, false);
125
126 if (!painting_overflow_contents) {
127 // FIXME: Should eventually give the theme control over whether the box
128 // shadow should paint, since controls could have custom shadows of their
129 // own.
130 PaintNormalBoxShadow(paint_info, paint_rect, style);
131
132 if (BleedAvoidanceIsClipping(box_decoration_data.bleed_avoidance)) {
133 state_saver.Save();
134 FloatRoundedRect border = style.GetRoundedBorderFor(paint_rect);
135 paint_info.context.ClipRoundedRect(border);
136
137 if (box_decoration_data.bleed_avoidance == kBackgroundBleedClipLayer)
138 paint_info.context.BeginLayer();
139 }
140 }
141
142 // TODO(layout-dev): Support theme painting.
143
144 // TODO(eae): Support SkipRootBackground painting.
145 bool should_paint_background = true;
146 if (should_paint_background) {
147 PaintBackground(paint_info, paint_rect,
148 box_decoration_data.background_color,
149 box_decoration_data.bleed_avoidance);
150 }
151
152 if (!painting_overflow_contents) {
153 PaintInsetBoxShadow(paint_info, paint_rect, style);
154
155 if (box_decoration_data.has_border_decoration) {
156 PaintBorder(box_fragment_, paint_info, paint_rect, style,
157 box_decoration_data.bleed_avoidance);
158 }
159 }
160
161 if (box_decoration_data.bleed_avoidance == kBackgroundBleedClipLayer)
162 paint_info.context.EndLayer();
163 }
164
165 void NGBoxFragmentPainter::PaintBackground(
166 const PaintInfo& paint_info,
167 const LayoutRect& paint_rect,
168 const Color& background_color,
169 BackgroundBleedAvoidance bleed_avoidance) {
170 // if (layout_box_.IsDocumentElement())
171 // return;
172 // if (layout_box_.BackgroundStolenForBeingBody())
173 // return;
174 // if (layout_box_.BackgroundIsKnownToBeObscured())
175 // return;
176 PaintFillLayers(paint_info, background_color,
177 box_fragment_->Style().BackgroundLayers(), paint_rect,
178 bleed_avoidance);
179 }
180
181 void NGBoxFragmentPainter::PaintFillLayers(
182 const PaintInfo& paint_info,
183 const Color& c,
184 const FillLayer& fill_layer,
185 const LayoutRect& rect,
186 BackgroundBleedAvoidance avoidance,
187 SkBlendMode op,
188 const NGPhysicalFragment* bg_fragment) {
189 FillLayerOcclusionOutputList reversed_paint_list;
190 bool should_draw_background_in_separate_buffer =
191 CalculateFillLayerOcclusionCulling(reversed_paint_list, fill_layer,
192 GetDocument(), box_fragment_->Style());
193
194 // TODO(trchen): We can optimize out isolation group if we have a
195 // non-transparent background color and the bottom layer encloses all other
196 // layers.
197
198 GraphicsContext& context = paint_info.context;
199
200 if (should_draw_background_in_separate_buffer)
201 context.BeginLayer();
202
203 for (auto it = reversed_paint_list.rbegin(); it != reversed_paint_list.rend();
204 ++it) {
205 PaintFillLayer(box_fragment_, paint_info, c, **it, rect, avoidance, 0,
206 LayoutSize(), op, bg_fragment);
207 }
208
209 if (should_draw_background_in_separate_buffer)
210 context.EndLayer();
211 }
212
213 namespace {
214
215 inline bool PaintFastBottomLayer(
216 const NGPhysicalBoxFragment* fragment,
217 const PaintInfo& paint_info,
218 const BoxPainterBase::FillLayerInfo& info,
219 const FillLayer& layer,
220 const LayoutRect& rect,
221 BackgroundBleedAvoidance bleed_avoidance,
222 bool has_line_box_sibling,
223 const LayoutSize& box_size,
224 SkBlendMode op,
225 const NGPhysicalFragment* background_fragment
226 /*Optional<BackgroundImageGeometry>& geometry*/) {
227 // Painting a background image from an ancestor onto a cell is a complex case.
228 // if (obj.IsTableCell() && bg_fragment &&
229 // !bg_fragment->IsTableCell())
230 // return false;
231 // Complex cases not handled on the fast path.
232 // if (!info.is_bottom_layer || !info.is_border_fill ||
233 // info.is_clipped_with_local_scrolling)
234 // return false;
235
236 // Transparent layer, nothing to paint.
237 if (!info.should_paint_color && !info.should_paint_image)
238 return true;
239
240 // When the layer has an image, figure out whether it is covered by a single
241 // tile.
242 FloatRect image_tile;
243 if (info.should_paint_image) {
244 // TODO(layout-dev): Add support for background images.
245 return false;
246 }
247
248 // At this point we're committed to the fast path: the destination (r)rect
249 // fits within a single tile, and we can paint it using direct draw(R)Rect()
250 // calls.
251 GraphicsContext& context = paint_info.context;
252 FloatRoundedRect border =
253 info.is_rounded_fill
254 ? BoxPainterBase::BackgroundRoundedRectAdjustedForBleedAvoidance(
255 fragment->Style(), rect, bleed_avoidance, has_line_box_sibling,
256 box_size, info.include_left_edge, info.include_right_edge)
257 : FloatRoundedRect(PixelSnappedIntRect(rect));
258
259 // Optional<RoundedInnerRectClipper> clipper;
260 // if (info.is_rounded_fill && !border.IsRenderable()) {
261 // When the rrect is not renderable, we resort to clipping.
262 // RoundedInnerRectClipper handles this case via discrete, corner-wise
263 // clipping.
264 // clipper.emplace(obj, paint_info, rect, border, kApplyToContext);
265 // border.SetRadii(FloatRoundedRect::Radii());
266 //}
267
268 // Paint the color if needed.
269 if (info.should_paint_color)
270 context.FillRoundedRect(border, info.color);
271
272 return true;
273 }
274
275 } // anonymous namespace
276
277 void NGBoxFragmentPainter::PaintFillLayer(
278 const NGPhysicalBoxFragment* fragment,
279 const PaintInfo& paint_info,
280 const Color& color,
281 const FillLayer& bg_layer,
282 const LayoutRect& rect,
283 BackgroundBleedAvoidance avoidance,
284 const NGPhysicalFragment* box,
285 const LayoutSize& box_size,
286 SkBlendMode op,
287 const NGPhysicalFragment* bg_fragment) {
288 GraphicsContext& context = paint_info.context;
289 const ComputedStyle& style = fragment->Style();
290 if (rect.IsEmpty())
291 return;
292
293 const BoxPainterBase::FillLayerInfo info(
294 fragment->GetLayoutObject()->GetDocument(), style,
295 fragment->HasOverflowClip(), color, bg_layer, avoidance,
296 box ? (box->BorderEdges() & NGPhysicalTextFragment::kLeftBorder) : true,
297 box ? (box->BorderEdges() & NGPhysicalTextFragment::kRightBorder) : true);
298
299 // Optional<BackgroundImageGeometry> geometry;
300 // bool has_line_box_sibling = box && (box->NextLineBox() ||
301 // box->PrevLineBox());
302 bool has_line_box_sibling = false;
303
304 // Fast path for drawing simple color backgrounds.
305 if (PaintFastBottomLayer(fragment, paint_info, info, bg_layer, rect,
306 avoidance, has_line_box_sibling, box_size, op,
307 bg_fragment)) {
308 return;
309 }
310
311 NGPixelSnappedPhysicalBoxStrut borders = fragment->BorderWidths();
312 NGPhysicalBoxStrut paddings; // TODO(layout-dev): Implement
313
314 Optional<RoundedInnerRectClipper> clip_to_border;
315 if (info.is_rounded_fill) {
316 FloatRoundedRect border =
317 info.is_border_fill
318 ? BackgroundRoundedRectAdjustedForBleedAvoidance(
319 style, rect, avoidance, has_line_box_sibling, box_size,
320 info.include_left_edge, info.include_right_edge)
321 : GetBackgroundRoundedRect(style, rect, has_line_box_sibling,
322 box_size, info.include_left_edge,
323 info.include_right_edge);
324
325 // Clip to the padding or content boxes as necessary.
326 if (bg_layer.Clip() == kContentFillBox) {
327 // TODO(layout-dev): Do we need to include the padding here?
328 LayoutRectOutsets border_inset(
329 LayoutUnit(borders.top), LayoutUnit(borders.right),
330 LayoutUnit(borders.bottom), LayoutUnit(borders.left));
331 border = style.GetRoundedInnerBorderFor(
332 LayoutRect(border.Rect()), border_inset, info.include_left_edge,
333 info.include_right_edge);
334 } else if (bg_layer.Clip() == kPaddingFillBox) {
335 border = style.GetRoundedInnerBorderFor(LayoutRect(border.Rect()),
336 info.include_left_edge,
337 info.include_right_edge);
338 }
339
340 clip_to_border.emplace(*fragment, paint_info, rect, border,
341 kApplyToContext);
342 }
343
344 GraphicsContextStateSaver clip_with_scrolling_state_saver(
345 context, info.is_clipped_with_local_scrolling);
346 LayoutRect scrolled_paint_rect = rect;
347 if (info.is_clipped_with_local_scrolling &&
348 !IsPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(
349 fragment, paint_info)) {
350 // Clip to the overflow area.
351 // TODO(chrishtr): this should be pixel-snapped.
352 // TODO(layout-dev): We don't know the location...
353 // context.Clip(FloatRect(this_box.OverflowClipRect(rect.Location())));
354
355 // Adjust the paint rect to reflect a scrolled content box with borders at
356 // the ends.
357 // TODO(layout_dev): Support scrolling
358 // IntSize offset = this_box.ScrolledContentOffset();
359 // scrolled_paint_rect.Move(-offset);
360 // scrolled_paint_rect.SetWidth(borders.left + this_box.ScrollWidth() +
361 // borders.right); scrolled_paint_rect.SetHeight(this_box.BorderTop() +
362 // this_box.ScrollHeight() +
363 // this_box.BorderBottom());
364 }
365
366 GraphicsContextStateSaver background_clip_state_saver(context, false);
367 IntRect mask_rect;
368
369 switch (bg_layer.Clip()) {
370 case kPaddingFillBox:
371 case kContentFillBox: {
372 if (info.is_rounded_fill)
373 break;
374
375 // Clip to the padding or content boxes as necessary.
376 bool include_padding = bg_layer.Clip() == kContentFillBox;
377 LayoutRect clip_rect(
378 scrolled_paint_rect.X() + borders.left,
379 scrolled_paint_rect.Y() + borders.top,
380 scrolled_paint_rect.Width() - borders.left - borders.right,
381 scrolled_paint_rect.Height() - borders.top - borders.bottom);
382
383 if (include_padding) {
384 clip_rect.ContractEdges(paddings.top, paddings.right, paddings.bottom,
385 paddings.left);
386 }
387
388 background_clip_state_saver.Save();
389 // TODO(chrishtr): this should be pixel-snapped.
390 context.Clip(FloatRect(clip_rect));
391
392 break;
393 }
394 case kTextFillBox: {
395 // First figure out how big the mask has to be. It should be no bigger
396 // than what we need to actually render, so we should intersect the dirty
397 // rect with the border box of the background.
398 mask_rect = PixelSnappedIntRect(rect);
399
400 // We draw the background into a separate layer, to be later masked with
401 // yet another layer holding the text content.
402 background_clip_state_saver.Save();
403 context.Clip(mask_rect);
404 context.BeginLayer();
405
406 break;
407 }
408 case kBorderFillBox:
409 break;
410 default:
411 NOTREACHED();
412 break;
413 }
414
415 // Paint the color first underneath all images, culled if background image
416 // occludes it.
417 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the
418 // culling test by verifying whether the background image covers the entire
419 // painting area.
420 if (info.is_bottom_layer && info.color.Alpha() && info.should_paint_color) {
421 IntRect background_rect(PixelSnappedIntRect(scrolled_paint_rect));
422 context.FillRect(background_rect, info.color);
423 }
424
425 // No progressive loading of the background image.
426 if (info.should_paint_image) {
427 // TODO(layout-dev): Add support for image painting.
428 DCHECK(false);
429 }
430
431 if (bg_layer.Clip() == kTextFillBox) {
432 // Create the text mask layer.
433 context.BeginLayer(1, SkBlendMode::kDstIn);
434
435 // Now draw the text into the mask. We do this by painting using a special
436 // paint phase that signals to
437 // InlineTextBoxes that they should just add their contents to the clip.
438 PaintInfo info(context, mask_rect, kPaintPhaseTextClip,
439 kGlobalPaintNormalPhase, 0);
440 // if (box) {
441 // const RootInlineBox& root = box->Root();
442 // box->Paint(info,
443 // LayoutPoint(scrolled_paint_rect.X() - box->X(),
444 // scrolled_paint_rect.Y() - box->Y()),
445 // root.LineTop(), root.LineBottom());
446 //} else {
447 // // FIXME: this should only have an effect for the line box list within
448 // // |obj|. Change this to create a LineBoxListPainter directly.
449 // LayoutSize local_offset =
450 // obj.IsBox() ? ToLayoutBox(&obj)->LocationOffset() : LayoutSize();
451 // obj.Paint(info, scrolled_paint_rect.Location() - local_offset);
452 //}
453
454 context.EndLayer();
455 context.EndLayer();
456 }
457 }
458
459 LayoutRect NGBoxFragmentPainter::BoundsForDrawingRecorder(
460 const PaintInfo& paint_info,
461 const LayoutPoint& adjusted_paint_offset) {
462 LayoutRect bounds = box_fragment_->VisualOverflowRect();
463 bounds.MoveBy(adjusted_paint_offset);
464 return bounds;
465 }
466
467 void NGBoxFragmentPainter::PaintBorder(const NGPhysicalBoxFragment* fragment,
468 const PaintInfo& info,
469 const LayoutRect& rect,
470 const ComputedStyle& style,
471 BackgroundBleedAvoidance bleed_avoidance,
472 bool include_logical_left_edge,
473 bool include_logical_right_edge) {
474 // TODO(layout-dev): Add support for image border painting.
475 const BoxBorderPainter border_painter(rect, style, bleed_avoidance,
476 include_logical_left_edge,
477 include_logical_right_edge);
478 border_painter.PaintBorder(info, rect);
479 }
480
481 const Document& NGBoxFragmentPainter::GetDocument() const {
482 return box_fragment_->GetLayoutObject()->GetDocument();
483 }
484
485 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698