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

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

Issue 2820743003: Paint text underline/overline decorations before painting text. (Closed)
Patch Set: Swap order of method definitions. Created 3 years, 8 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
« no previous file with comments | « third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/paint/InlineTextBoxPainter.h" 5 #include "core/paint/InlineTextBoxPainter.h"
6 6
7 #include "core/editing/CompositionUnderline.h" 7 #include "core/editing/CompositionUnderline.h"
8 #include "core/editing/Editor.h" 8 #include "core/editing/Editor.h"
9 #include "core/editing/markers/DocumentMarkerController.h" 9 #include "core/editing/markers/DocumentMarkerController.h"
10 #include "core/frame/LocalFrame.h" 10 #include "core/frame/LocalFrame.h"
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 209
210 // Each Bezier curve starts at the same pixel that the previous one 210 // Each Bezier curve starts at the same pixel that the previous one
211 // ended. We need to subtract (stepCount - 1) pixels when calculating the 211 // ended. We need to subtract (stepCount - 1) pixels when calculating the
212 // length covered to account for that. 212 // length covered to account for that.
213 float uncovered_length = length - (step_count * step - (step_count - 1)); 213 float uncovered_length = length - (step_count * step - (step_count - 1));
214 float adjustment = uncovered_length / step_count; 214 float adjustment = uncovered_length / step_count;
215 step += adjustment; 215 step += adjustment;
216 control_point_distance += adjustment; 216 control_point_distance += adjustment;
217 } 217 }
218 218
219 // Holds text decoration painting values to be computed once and subsequently
220 // use multiple times to handle decoration paint order correctly. See also
221 // https://www.w3.org/TR/css-text-decor-3/#painting-order
222 struct DecorationInfo final {
223 STACK_ALLOCATED();
224
225 LayoutUnit width;
226 FloatPoint local_origin;
227 bool antialias;
228 float baseline;
229 const ComputedStyle* style;
230 const SimpleFontData* font_data;
231 float thickness;
232 float double_offset;
233 };
234
219 class AppliedDecorationPainter final { 235 class AppliedDecorationPainter final {
220 STACK_ALLOCATED(); 236 STACK_ALLOCATED();
221 237
222 public: 238 public:
223 AppliedDecorationPainter(GraphicsContext& context, 239 AppliedDecorationPainter(GraphicsContext& context,
224 FloatPoint start_point, 240 const DecorationInfo& decoration_info,
225 float width, 241 int start_point_y_offset,
226 const AppliedTextDecoration& decoration, 242 const AppliedTextDecoration& decoration,
227 float thickness,
228 float double_offset, 243 float double_offset,
229 int wavy_offset_factor, 244 int wavy_offset_factor)
230 bool antialias_decoration)
231 : context_(context), 245 : context_(context),
232 start_point_(start_point), 246 start_point_(decoration_info.local_origin +
233 width_(width), 247 FloatPoint(0, start_point_y_offset)),
248 decoration_info_(decoration_info),
234 decoration_(decoration), 249 decoration_(decoration),
235 thickness_(thickness),
236 double_offset_(double_offset), 250 double_offset_(double_offset),
237 wavy_offset_factor_(wavy_offset_factor), 251 wavy_offset_factor_(wavy_offset_factor){};
238 should_antialias_(antialias_decoration){};
239 252
240 void Paint(); 253 void Paint();
241 FloatRect DecorationBounds(); 254 FloatRect DecorationBounds();
242 255
243 private: 256 private:
244 void StrokeWavyTextDecoration(); 257 void StrokeWavyTextDecoration();
245 258
246 Path PrepareWavyStrokePath(); 259 Path PrepareWavyStrokePath();
247 Path PrepareDottedDashedStrokePath(); 260 Path PrepareDottedDashedStrokePath();
248 261
249 GraphicsContext& context_; 262 GraphicsContext& context_;
250 FloatPoint start_point_; 263 const FloatPoint start_point_;
251 float width_; 264 const DecorationInfo& decoration_info_;
252 const AppliedTextDecoration& decoration_; 265 const AppliedTextDecoration& decoration_;
253 float thickness_;
254 const float double_offset_; 266 const float double_offset_;
255 const int wavy_offset_factor_; 267 const int wavy_offset_factor_;
256 bool should_antialias_;
257 }; 268 };
258 269
259 Path AppliedDecorationPainter::PrepareDottedDashedStrokePath() { 270 Path AppliedDecorationPainter::PrepareDottedDashedStrokePath() {
260 // These coordinate transforms need to match what's happening in 271 // These coordinate transforms need to match what's happening in
261 // GraphicsContext's drawLineForText and drawLine. 272 // GraphicsContext's drawLineForText and drawLine.
262 int y = floorf(start_point_.Y() + std::max<float>(thickness_ / 2.0f, 0.5f)); 273 int y = floorf(start_point_.Y() +
274 std::max<float>(decoration_info_.thickness / 2.0f, 0.5f));
263 Path stroke_path; 275 Path stroke_path;
264 FloatPoint rounded_start_point(start_point_.X(), y); 276 FloatPoint rounded_start_point(start_point_.X(), y);
265 FloatPoint rounded_end_point(rounded_start_point + FloatPoint(width_, 0)); 277 FloatPoint rounded_end_point(rounded_start_point +
278 FloatPoint(decoration_info_.width, 0));
266 context_.AdjustLineToPixelBoundaries(rounded_start_point, rounded_end_point, 279 context_.AdjustLineToPixelBoundaries(rounded_start_point, rounded_end_point,
267 roundf(thickness_), 280 roundf(decoration_info_.thickness),
268 context_.GetStrokeStyle()); 281 context_.GetStrokeStyle());
269 stroke_path.MoveTo(rounded_start_point); 282 stroke_path.MoveTo(rounded_start_point);
270 stroke_path.AddLineTo(rounded_end_point); 283 stroke_path.AddLineTo(rounded_end_point);
271 return stroke_path; 284 return stroke_path;
272 } 285 }
273 286
274 FloatRect AppliedDecorationPainter::DecorationBounds() { 287 FloatRect AppliedDecorationPainter::DecorationBounds() {
275 StrokeData stroke_data; 288 StrokeData stroke_data;
276 stroke_data.SetThickness(thickness_); 289 stroke_data.SetThickness(decoration_info_.thickness);
277 290
278 switch (decoration_.Style()) { 291 switch (decoration_.Style()) {
279 case kTextDecorationStyleDotted: 292 case kTextDecorationStyleDotted:
280 case kTextDecorationStyleDashed: { 293 case kTextDecorationStyleDashed: {
281 stroke_data.SetStyle( 294 stroke_data.SetStyle(
282 TextDecorationStyleToStrokeStyle(decoration_.Style())); 295 TextDecorationStyleToStrokeStyle(decoration_.Style()));
283 return PrepareDottedDashedStrokePath().StrokeBoundingRect( 296 return PrepareDottedDashedStrokePath().StrokeBoundingRect(
284 stroke_data, Path::BoundsType::kExact); 297 stroke_data, Path::BoundsType::kExact);
285 } 298 }
286 case kTextDecorationStyleWavy: 299 case kTextDecorationStyleWavy:
287 return PrepareWavyStrokePath().StrokeBoundingRect( 300 return PrepareWavyStrokePath().StrokeBoundingRect(
288 stroke_data, Path::BoundsType::kExact); 301 stroke_data, Path::BoundsType::kExact);
289 break; 302 break;
290 case kTextDecorationStyleDouble: 303 case kTextDecorationStyleDouble:
291 if (double_offset_ > 0) { 304 if (double_offset_ > 0) {
292 return FloatRect(start_point_.X(), start_point_.Y(), width_, 305 return FloatRect(start_point_.X(), start_point_.Y(),
293 double_offset_ + thickness_); 306 decoration_info_.width,
307 double_offset_ + decoration_info_.thickness);
294 } 308 }
295 return FloatRect(start_point_.X(), start_point_.Y() + double_offset_, 309 return FloatRect(start_point_.X(), start_point_.Y() + double_offset_,
296 width_, -double_offset_ + thickness_); 310 decoration_info_.width,
311 -double_offset_ + decoration_info_.thickness);
297 break; 312 break;
298 case kTextDecorationStyleSolid: 313 case kTextDecorationStyleSolid:
299 return FloatRect(start_point_.X(), start_point_.Y(), width_, thickness_); 314 return FloatRect(start_point_.X(), start_point_.Y(),
315 decoration_info_.width, decoration_info_.thickness);
300 default: 316 default:
301 break; 317 break;
302 } 318 }
303 NOTREACHED(); 319 NOTREACHED();
304 return FloatRect(); 320 return FloatRect();
305 } 321 }
306 322
307 void AppliedDecorationPainter::Paint() { 323 void AppliedDecorationPainter::Paint() {
308 context_.SetStrokeStyle( 324 context_.SetStrokeStyle(
309 TextDecorationStyleToStrokeStyle(decoration_.Style())); 325 TextDecorationStyleToStrokeStyle(decoration_.Style()));
310 context_.SetStrokeColor(decoration_.GetColor()); 326 context_.SetStrokeColor(decoration_.GetColor());
311 327
312 switch (decoration_.Style()) { 328 switch (decoration_.Style()) {
313 case kTextDecorationStyleWavy: 329 case kTextDecorationStyleWavy:
314 StrokeWavyTextDecoration(); 330 StrokeWavyTextDecoration();
315 break; 331 break;
316 case kTextDecorationStyleDotted: 332 case kTextDecorationStyleDotted:
317 case kTextDecorationStyleDashed: 333 case kTextDecorationStyleDashed:
318 context_.SetShouldAntialias(should_antialias_); 334 context_.SetShouldAntialias(decoration_info_.antialias);
319 // Fall through 335 // Fall through
320 default: 336 default:
321 context_.DrawLineForText(start_point_, width_); 337 context_.DrawLineForText(start_point_, decoration_info_.width);
322 338
323 if (decoration_.Style() == kTextDecorationStyleDouble) { 339 if (decoration_.Style() == kTextDecorationStyleDouble) {
324 context_.DrawLineForText(start_point_ + FloatPoint(0, double_offset_), 340 context_.DrawLineForText(start_point_ + FloatPoint(0, double_offset_),
325 width_); 341 decoration_info_.width);
326 } 342 }
327 } 343 }
328 } 344 }
329 345
330 void AppliedDecorationPainter::StrokeWavyTextDecoration() { 346 void AppliedDecorationPainter::StrokeWavyTextDecoration() {
331 context_.SetShouldAntialias(true); 347 context_.SetShouldAntialias(true);
332 context_.StrokePath(PrepareWavyStrokePath()); 348 context_.StrokePath(PrepareWavyStrokePath());
333 } 349 }
334 350
335 /* 351 /*
(...skipping 19 matching lines...) Expand all
355 * | 371 * |
356 * + - 372 * + -
357 * controlPoint2 373 * controlPoint2
358 * 374 *
359 * |-----------| 375 * |-----------|
360 * step 376 * step
361 */ 377 */
362 Path AppliedDecorationPainter::PrepareWavyStrokePath() { 378 Path AppliedDecorationPainter::PrepareWavyStrokePath() {
363 FloatPoint p1(start_point_ + 379 FloatPoint p1(start_point_ +
364 FloatPoint(0, double_offset_ * wavy_offset_factor_)); 380 FloatPoint(0, double_offset_ * wavy_offset_factor_));
365 FloatPoint p2(start_point_ + 381 FloatPoint p2(
366 FloatPoint(width_, double_offset_ * wavy_offset_factor_)); 382 start_point_ +
383 FloatPoint(decoration_info_.width, double_offset_ * wavy_offset_factor_));
367 384
368 context_.AdjustLineToPixelBoundaries(p1, p2, thickness_, 385 context_.AdjustLineToPixelBoundaries(p1, p2, decoration_info_.thickness,
369 context_.GetStrokeStyle()); 386 context_.GetStrokeStyle());
370 387
371 Path path; 388 Path path;
372 path.MoveTo(p1); 389 path.MoveTo(p1);
373 390
374 // Distance between decoration's axis and Bezier curve's control points. 391 // Distance between decoration's axis and Bezier curve's control points.
375 // The height of the curve is based on this distance. Use a minimum of 6 392 // The height of the curve is based on this distance. Use a minimum of 6
376 // pixels distance since 393 // pixels distance since
377 // the actual curve passes approximately at half of that distance, that is 3 394 // the actual curve passes approximately at half of that distance, that is 3
378 // pixels. 395 // pixels.
379 // The minimum height of the curve is also approximately 3 pixels. Increases 396 // The minimum height of the curve is also approximately 3 pixels. Increases
380 // the curve's height 397 // the curve's height
381 // as strockThickness increases to make the curve looks better. 398 // as strockThickness increases to make the curve looks better.
382 float control_point_distance = 3 * std::max<float>(2, thickness_); 399 float control_point_distance =
400 3 * std::max<float>(2, decoration_info_.thickness);
383 401
384 // Increment used to form the diamond shape between start point (p1), control 402 // Increment used to form the diamond shape between start point (p1), control
385 // points and end point (p2) along the axis of the decoration. Makes the 403 // points and end point (p2) along the axis of the decoration. Makes the
386 // curve wider as strockThickness increases to make the curve looks better. 404 // curve wider as strockThickness increases to make the curve looks better.
387 float step = 2 * std::max<float>(2, thickness_); 405 float step = 2 * std::max<float>(2, decoration_info_.thickness);
388 406
389 bool is_vertical_line = (p1.X() == p2.X()); 407 bool is_vertical_line = (p1.X() == p2.X());
390 408
391 if (is_vertical_line) { 409 if (is_vertical_line) {
392 DCHECK(p1.X() == p2.X()); 410 DCHECK(p1.X() == p2.X());
393 411
394 float x_axis = p1.X(); 412 float x_axis = p1.X();
395 float y1; 413 float y1;
396 float y2; 414 float y2;
397 415
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 478
461 static bool PaintsCompositionMarkers(const LayoutObject& layout_object) { 479 static bool PaintsCompositionMarkers(const LayoutObject& layout_object) {
462 return layout_object.GetNode() && 480 return layout_object.GetNode() &&
463 layout_object.GetDocument() 481 layout_object.GetDocument()
464 .Markers() 482 .Markers()
465 .MarkersFor(layout_object.GetNode(), 483 .MarkersFor(layout_object.GetNode(),
466 DocumentMarker::kComposition) 484 DocumentMarker::kComposition)
467 .size() > 0; 485 .size() > 0;
468 } 486 }
469 487
488 static void PrepareContextForDecoration(GraphicsContext& context,
489 GraphicsContextStateSaver& state_saver,
490 bool is_horizontal,
491 const TextPainter::Style& text_style,
492 const LayoutTextCombine* combined_text,
493 const LayoutRect& box_rect) {
494 TextPainter::UpdateGraphicsContext(context, text_style, is_horizontal,
495 state_saver);
496 if (combined_text)
497 context.ConcatCTM(TextPainter::Rotation(box_rect, TextPainter::kClockwise));
498 }
499
500 static void RestoreContextFromDecoration(GraphicsContext& context,
501 const LayoutTextCombine* combined_text,
502 const LayoutRect& box_rect) {
503 if (combined_text) {
504 context.ConcatCTM(
505 TextPainter::Rotation(box_rect, TextPainter::kCounterclockwise));
506 }
507 }
508
509 static void ComputeDecorationInfo(
wkorman 2017/04/15 03:01:03 I made this (and the two paint methods below) stat
510 DecorationInfo& decoration_info,
511 const InlineTextBox& box,
512 const LayoutPoint& box_origin,
513 const Vector<AppliedTextDecoration>& decorations) {
514 LayoutPoint local_origin = LayoutPoint(box_origin);
515 LayoutUnit width = box.LogicalWidth();
516 if (box.Truncation() != kCNoTruncation) {
517 bool ltr = box.IsLeftToRightDirection();
518 bool flow_is_ltr =
519 box.GetLineLayoutItem().Style()->IsLeftToRightDirection();
520 width = LayoutUnit(box.GetLineLayoutItem().Width(
521 ltr == flow_is_ltr ? box.Start() : box.Start() + box.Truncation(),
522 ltr == flow_is_ltr ? box.Truncation() : box.Len() - box.Truncation(),
523 box.TextPos(), flow_is_ltr ? TextDirection::kLtr : TextDirection::kRtl,
524 box.IsFirstLineStyle()));
525 if (!flow_is_ltr) {
526 local_origin.Move(box.LogicalWidth() - width, LayoutUnit());
527 }
528 }
529 decoration_info.width = width;
530 decoration_info.local_origin = FloatPoint(local_origin);
531
532 decoration_info.antialias = ShouldSetDecorationAntialias(decorations);
533
534 decoration_info.style =
535 LineLayoutAPIShim::LayoutObjectFrom(box.GetLineLayoutItem())
536 ->Style(box.IsFirstLineStyle());
537 decoration_info.font_data = decoration_info.style->GetFont().PrimaryFont();
538 DCHECK(decoration_info.font_data);
539 decoration_info.baseline =
540 decoration_info.font_data
541 ? decoration_info.font_data->GetFontMetrics().FloatAscent()
542 : 0;
543
544 // Set the thick of the line to be 10% (or something else ?)of the computed
545 // font size and not less than 1px. Using computedFontSize should take care
546 // of zoom as well.
547
548 // Update Underline thickness, in case we have Faulty Font Metrics calculating
549 // underline thickness by old method.
550 float text_decoration_thickness = 0.0;
551 int font_height_int = 0;
552 if (decoration_info.font_data) {
553 text_decoration_thickness =
554 decoration_info.font_data->GetFontMetrics().UnderlineThickness();
555 font_height_int =
556 (int)(decoration_info.font_data->GetFontMetrics().FloatHeight() + 0.5);
557 }
558 if ((text_decoration_thickness == 0.f) ||
559 (text_decoration_thickness >= (font_height_int >> 1))) {
560 text_decoration_thickness =
561 std::max(1.f, decoration_info.style->ComputedFontSize() / 10.f);
562 }
563 decoration_info.thickness = text_decoration_thickness;
564
565 // Offset between lines - always non-zero, so lines never cross each other.
566 decoration_info.double_offset = text_decoration_thickness + 1.f;
567 }
568
569 static void PaintDecorationsExceptLineThrough(
570 TextPainter& text_painter,
571 bool& has_line_through_decoration,
572 const InlineTextBox& box,
573 const DecorationInfo& decoration_info,
574 const PaintInfo& paint_info,
575 const Vector<AppliedTextDecoration>& decorations) {
576 GraphicsContext& context = paint_info.context;
577 GraphicsContextStateSaver state_saver(context);
578 context.SetStrokeThickness(decoration_info.thickness);
579 bool skip_intercepts =
580 decoration_info.style->GetTextDecorationSkip() & kTextDecorationSkipInk;
581
582 // text-underline-position may flip underline and overline.
583 ResolvedUnderlinePosition underline_position =
584 ResolveUnderlinePosition(*decoration_info.style, &box);
585 bool flip_underline_and_overline = false;
586 if (underline_position == ResolvedUnderlinePosition::kOver) {
587 flip_underline_and_overline = true;
588 underline_position = ResolvedUnderlinePosition::kUnder;
589 }
590
591 for (const AppliedTextDecoration& decoration : decorations) {
592 TextDecoration lines = decoration.Lines();
593 if (flip_underline_and_overline) {
594 lines = static_cast<TextDecoration>(
595 lines ^ (kTextDecorationUnderline | kTextDecorationOverline));
596 }
597 if ((lines & kTextDecorationUnderline) && decoration_info.font_data) {
598 const int underline_offset =
599 ComputeUnderlineOffset(underline_position, *decoration_info.style,
600 decoration_info.font_data->GetFontMetrics(),
601 &box, decoration_info.thickness);
602 AppliedDecorationPainter decoration_painter(
603 context, decoration_info, underline_offset, decoration,
604 decoration_info.double_offset, 1);
605 if (skip_intercepts) {
606 text_painter.ClipDecorationsStripe(
607 -decoration_info.baseline +
608 decoration_painter.DecorationBounds().Y() -
609 decoration_info.local_origin.Y(),
610 decoration_painter.DecorationBounds().Height(),
611 decoration_info.thickness);
612 }
613 decoration_painter.Paint();
614 }
615 if (lines & kTextDecorationOverline) {
616 const int overline_offset =
617 ComputeOverlineOffset(*decoration_info.style, &box);
618 AppliedDecorationPainter decoration_painter(
619 context, decoration_info, overline_offset, decoration,
620 -decoration_info.double_offset, 1);
621 if (skip_intercepts) {
622 text_painter.ClipDecorationsStripe(
623 -decoration_info.baseline +
624 decoration_painter.DecorationBounds().Y() -
625 decoration_info.local_origin.Y(),
626 decoration_painter.DecorationBounds().Height(),
627 decoration_info.thickness);
628 }
629 decoration_painter.Paint();
630 }
631 // We could instead build a vector of the TextDecoration instances needing
632 // line-through but this is a rare case so better to avoid vector overhead.
633 has_line_through_decoration |= (lines & kTextDecorationLineThrough);
634 }
635 }
636
637 static void PaintDecorationsOnlyLineThrough(
638 TextPainter& text_painter,
639 const DecorationInfo& decoration_info,
640 const PaintInfo& paint_info,
641 const Vector<AppliedTextDecoration>& decorations) {
642 GraphicsContext& context = paint_info.context;
643 GraphicsContextStateSaver state_saver(context);
644 context.SetStrokeThickness(decoration_info.thickness);
645 for (const AppliedTextDecoration& decoration : decorations) {
646 TextDecoration lines = decoration.Lines();
647 if (lines & kTextDecorationLineThrough) {
648 const float line_through_offset = 2 * decoration_info.baseline / 3;
649 AppliedDecorationPainter decoration_painter(
650 context, decoration_info, line_through_offset, decoration,
651 decoration_info.double_offset, 0);
652 // No skip: ink for line-through,
653 // compare https://github.com/w3c/csswg-drafts/issues/711
654 decoration_painter.Paint();
655 }
656 }
657 }
658
470 void InlineTextBoxPainter::Paint(const PaintInfo& paint_info, 659 void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
471 const LayoutPoint& paint_offset) { 660 const LayoutPoint& paint_offset) {
472 if (!ShouldPaintTextBox(paint_info)) 661 if (!ShouldPaintTextBox(paint_info))
473 return; 662 return;
474 663
475 DCHECK(!ShouldPaintSelfOutline(paint_info.phase) && 664 DCHECK(!ShouldPaintSelfOutline(paint_info.phase) &&
476 !ShouldPaintDescendantOutlines(paint_info.phase)); 665 !ShouldPaintDescendantOutlines(paint_info.phase));
477 666
478 LayoutRect logical_visual_overflow = inline_text_box_.LogicalOverflowRect(); 667 LayoutRect logical_visual_overflow = inline_text_box_.LogicalOverflowRect();
479 LayoutUnit logical_start = 668 LayoutUnit logical_start =
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
662 style_to_use, emphasis_mark_position); 851 style_to_use, emphasis_mark_position);
663 if (has_text_emphasis) 852 if (has_text_emphasis)
664 text_painter.SetEmphasisMark(style_to_use.TextEmphasisMarkString(), 853 text_painter.SetEmphasisMark(style_to_use.TextEmphasisMarkString(),
665 emphasis_mark_position); 854 emphasis_mark_position);
666 if (combined_text) 855 if (combined_text)
667 text_painter.SetCombinedText(combined_text); 856 text_painter.SetCombinedText(combined_text);
668 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr) 857 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr)
669 text_painter.SetEllipsisOffset(inline_text_box_.Truncation()); 858 text_painter.SetEllipsisOffset(inline_text_box_.Truncation());
670 859
671 if (!paint_selected_text_only) { 860 if (!paint_selected_text_only) {
861 // Paint text decorations except line-through.
862 DecorationInfo decoration_info;
wkorman 2017/04/15 03:01:03 I had this as an Optional (see two patchsets previ
863 bool has_line_through_decoration = false;
864 if (style_to_use.TextDecorationsInEffect() != kTextDecorationNone &&
865 inline_text_box_.Truncation() != kCFullTruncation) {
866 ComputeDecorationInfo(decoration_info, inline_text_box_, box_origin,
867 style_to_use.AppliedTextDecorations());
868 GraphicsContextStateSaver state_saver(context, false);
869 PrepareContextForDecoration(context, state_saver,
870 inline_text_box_.IsHorizontal(), text_style,
871 combined_text, box_rect);
872 PaintDecorationsExceptLineThrough(
873 text_painter, has_line_through_decoration, inline_text_box_,
874 decoration_info, paint_info, style_to_use.AppliedTextDecorations());
875 RestoreContextFromDecoration(context, combined_text, box_rect);
876 }
877
672 int start_offset = 0; 878 int start_offset = 0;
673 int end_offset = length; 879 int end_offset = length;
674 // Where the text and its flow have opposite directions then our offset into 880 // Where the text and its flow have opposite directions then our offset into
675 // the text given by |truncation| is at the start of the part that will be 881 // the text given by |truncation| is at the start of the part that will be
676 // visible. 882 // visible.
677 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr) { 883 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr) {
678 start_offset = inline_text_box_.Truncation(); 884 start_offset = inline_text_box_.Truncation();
679 end_offset = text_run.length(); 885 end_offset = text_run.length();
680 } 886 }
681 887
682 if (paint_selected_text_separately && selection_start < selection_end) { 888 if (paint_selected_text_separately && selection_start < selection_end) {
683 start_offset = selection_end; 889 start_offset = selection_end;
684 end_offset = selection_start; 890 end_offset = selection_start;
685 } 891 }
686 892
687 text_painter.Paint(start_offset, end_offset, length, text_style); 893 text_painter.Paint(start_offset, end_offset, length, text_style);
894
895 // Paint line-through decoration if needed.
896 if (has_line_through_decoration) {
897 GraphicsContextStateSaver state_saver(context, false);
898 PrepareContextForDecoration(context, state_saver,
899 inline_text_box_.IsHorizontal(), text_style,
900 combined_text, box_rect);
901 PaintDecorationsOnlyLineThrough(text_painter, decoration_info, paint_info,
902 style_to_use.AppliedTextDecorations());
903 RestoreContextFromDecoration(context, combined_text, box_rect);
904 }
688 } 905 }
689 906
690 if ((paint_selected_text_only || paint_selected_text_separately) && 907 if ((paint_selected_text_only || paint_selected_text_separately) &&
691 selection_start < selection_end) { 908 selection_start < selection_end) {
692 // paint only the text that is selected 909 // paint only the text that is selected
693 text_painter.Paint(selection_start, selection_end, length, selection_style); 910 text_painter.Paint(selection_start, selection_end, length, selection_style);
694 } 911 }
695 912
696 // Paint decorations
697 if (style_to_use.TextDecorationsInEffect() != kTextDecorationNone &&
698 !paint_selected_text_only) {
699 GraphicsContextStateSaver state_saver(context, false);
700
701 TextPainter::UpdateGraphicsContext(
702 context, text_style, inline_text_box_.IsHorizontal(), state_saver);
703
704 if (combined_text)
705 context.ConcatCTM(
706 TextPainter::Rotation(box_rect, TextPainter::kClockwise));
707 PaintDecorations(text_painter, paint_info, box_origin,
708 style_to_use.AppliedTextDecorations());
709 if (combined_text)
710 context.ConcatCTM(
711 TextPainter::Rotation(box_rect, TextPainter::kCounterclockwise));
712 }
713
714 if (paint_info.phase == kPaintPhaseForeground) 913 if (paint_info.phase == kPaintPhaseForeground)
715 PaintDocumentMarkers(paint_info, box_origin, style_to_use, font, 914 PaintDocumentMarkers(paint_info, box_origin, style_to_use, font,
716 DocumentMarkerPaintPhase::kForeground); 915 DocumentMarkerPaintPhase::kForeground);
717 916
718 if (should_rotate) 917 if (should_rotate)
719 context.ConcatCTM( 918 context.ConcatCTM(
720 TextPainter::Rotation(box_rect, TextPainter::kCounterclockwise)); 919 TextPainter::Rotation(box_rect, TextPainter::kCounterclockwise));
721 } 920 }
722 921
723 bool InlineTextBoxPainter::ShouldPaintTextBox(const PaintInfo& paint_info) { 922 bool InlineTextBoxPainter::ShouldPaintTextBox(const PaintInfo& paint_info) {
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 LayoutRect& rect) { 1299 LayoutRect& rect) {
1101 FloatRectOutsets outsets = FloatRectOutsets(); 1300 FloatRectOutsets outsets = FloatRectOutsets();
1102 float space_width = inline_text_box_.NewlineSpaceWidth(); 1301 float space_width = inline_text_box_.NewlineSpaceWidth();
1103 if (inline_text_box_.IsLeftToRightDirection()) 1302 if (inline_text_box_.IsLeftToRightDirection())
1104 outsets.SetRight(space_width); 1303 outsets.SetRight(space_width);
1105 else 1304 else
1106 outsets.SetLeft(space_width); 1305 outsets.SetLeft(space_width);
1107 rect.Expand(outsets); 1306 rect.Expand(outsets);
1108 } 1307 }
1109 1308
1110 void InlineTextBoxPainter::PaintDecorations(
1111 TextPainter& text_painter,
1112 const PaintInfo& paint_info,
1113 const LayoutPoint& box_origin,
1114 const Vector<AppliedTextDecoration>& decorations) {
1115 if (inline_text_box_.Truncation() == kCFullTruncation)
1116 return;
1117
1118 GraphicsContext& context = paint_info.context;
1119 GraphicsContextStateSaver state_saver(context);
1120
1121 LayoutPoint local_origin(box_origin);
1122
1123 LayoutUnit width = inline_text_box_.LogicalWidth();
1124 if (inline_text_box_.Truncation() != kCNoTruncation) {
1125 bool ltr = inline_text_box_.IsLeftToRightDirection();
1126 bool flow_is_ltr =
1127 inline_text_box_.GetLineLayoutItem().Style()->IsLeftToRightDirection();
1128 width = LayoutUnit(inline_text_box_.GetLineLayoutItem().Width(
1129 ltr == flow_is_ltr
1130 ? inline_text_box_.Start()
1131 : inline_text_box_.Start() + inline_text_box_.Truncation(),
1132 ltr == flow_is_ltr
1133 ? inline_text_box_.Truncation()
1134 : inline_text_box_.Len() - inline_text_box_.Truncation(),
1135 inline_text_box_.TextPos(),
1136 flow_is_ltr ? TextDirection::kLtr : TextDirection::kRtl,
1137 inline_text_box_.IsFirstLineStyle()));
1138 if (!flow_is_ltr)
1139 local_origin.Move(inline_text_box_.LogicalWidth() - width, LayoutUnit());
1140 }
1141
1142 LayoutObject& text_box_layout_object = InlineLayoutObject();
1143
1144 const ComputedStyle& style_to_use =
1145 text_box_layout_object.StyleRef(inline_text_box_.IsFirstLineStyle());
1146 const SimpleFontData* font_data = style_to_use.GetFont().PrimaryFont();
1147 DCHECK(font_data);
1148 float baseline = font_data ? font_data->GetFontMetrics().FloatAscent() : 0;
1149
1150 // Set the thick of the line to be 10% (or something else ?)of the computed
1151 // font size and not less than 1px. Using computedFontSize should take care
1152 // of zoom as well.
1153
1154 // Update Underline thickness, in case we have Faulty Font Metrics calculating
1155 // underline thickness by old method.
1156 float text_decoration_thickness = 0.0;
1157 int font_height_int = 0;
1158 if (font_data) {
1159 text_decoration_thickness =
1160 font_data->GetFontMetrics().UnderlineThickness();
1161 font_height_int = (int)(font_data->GetFontMetrics().FloatHeight() + 0.5);
1162 }
1163 if ((text_decoration_thickness == 0.f) ||
1164 (text_decoration_thickness >= (font_height_int >> 1)))
1165 text_decoration_thickness =
1166 std::max(1.f, style_to_use.ComputedFontSize() / 10.f);
1167
1168 context.SetStrokeThickness(text_decoration_thickness);
1169
1170 bool antialias_decoration = ShouldSetDecorationAntialias(decorations);
1171
1172 // Offset between lines - always non-zero, so lines never cross each other.
1173 float double_offset = text_decoration_thickness + 1.f;
1174 bool skip_intercepts =
1175 style_to_use.GetTextDecorationSkip() & kTextDecorationSkipInk;
1176
1177 // text-underline-position may flip underline and overline.
1178 ResolvedUnderlinePosition underline_position =
1179 ResolveUnderlinePosition(style_to_use, &inline_text_box_);
1180 bool flip_underline_and_overline = false;
1181 if (underline_position == ResolvedUnderlinePosition::kOver) {
1182 flip_underline_and_overline = true;
1183 underline_position = ResolvedUnderlinePosition::kUnder;
1184 }
1185
1186 for (const AppliedTextDecoration& decoration : decorations) {
1187 TextDecoration lines = decoration.Lines();
1188 if (flip_underline_and_overline) {
1189 lines = static_cast<TextDecoration>(
1190 lines ^ (kTextDecorationUnderline | kTextDecorationOverline));
1191 }
1192 if ((lines & kTextDecorationUnderline) && font_data) {
1193 const int underline_offset = ComputeUnderlineOffset(
1194 underline_position, style_to_use, font_data->GetFontMetrics(),
1195 &inline_text_box_, text_decoration_thickness);
1196 AppliedDecorationPainter decoration_painter(
1197 context, FloatPoint(local_origin) + FloatPoint(0, underline_offset),
1198 width.ToFloat(), decoration, text_decoration_thickness, double_offset,
1199 1, antialias_decoration);
1200 if (skip_intercepts) {
1201 text_painter.ClipDecorationsStripe(
1202 -baseline + decoration_painter.DecorationBounds().Y() -
1203 FloatPoint(local_origin).Y(),
1204 decoration_painter.DecorationBounds().Height(),
1205 text_decoration_thickness);
1206 }
1207 decoration_painter.Paint();
1208 }
1209 if (lines & kTextDecorationOverline) {
1210 const int overline_offset =
1211 ComputeOverlineOffset(style_to_use, &inline_text_box_);
1212 AppliedDecorationPainter decoration_painter(
1213 context, FloatPoint(local_origin) + FloatPoint(0, overline_offset),
1214 width.ToFloat(), decoration, text_decoration_thickness,
1215 -double_offset, 1, antialias_decoration);
1216 if (skip_intercepts) {
1217 text_painter.ClipDecorationsStripe(
1218 -baseline + decoration_painter.DecorationBounds().Y() -
1219 FloatPoint(local_origin).Y(),
1220 decoration_painter.DecorationBounds().Height(),
1221 text_decoration_thickness);
1222 }
1223 decoration_painter.Paint();
1224 }
1225 if (lines & kTextDecorationLineThrough) {
1226 const float line_through_offset = 2 * baseline / 3;
1227 AppliedDecorationPainter decoration_painter(
1228 context,
1229 FloatPoint(local_origin) + FloatPoint(0, line_through_offset),
1230 width.ToFloat(), decoration, text_decoration_thickness, double_offset,
1231 0, antialias_decoration);
1232 // No skip: ink for line-through,
1233 // compare https://github.com/w3c/csswg-drafts/issues/711
1234 decoration_painter.Paint();
1235 }
1236 }
1237 }
1238
1239 void InlineTextBoxPainter::PaintCompositionUnderline( 1309 void InlineTextBoxPainter::PaintCompositionUnderline(
1240 GraphicsContext& context, 1310 GraphicsContext& context,
1241 const LayoutPoint& box_origin, 1311 const LayoutPoint& box_origin,
1242 const CompositionUnderline& underline) { 1312 const CompositionUnderline& underline) {
1243 if (underline.GetColor() == Color::kTransparent) 1313 if (underline.GetColor() == Color::kTransparent)
1244 return; 1314 return;
1245 1315
1246 if (inline_text_box_.Truncation() == kCFullTruncation) 1316 if (inline_text_box_.Truncation() == kCFullTruncation)
1247 return; 1317 return;
1248 1318
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1384 1454
1385 LayoutRect box_rect(box_origin, LayoutSize(inline_text_box_.LogicalWidth(), 1455 LayoutRect box_rect(box_origin, LayoutSize(inline_text_box_.LogicalWidth(),
1386 inline_text_box_.LogicalHeight())); 1456 inline_text_box_.LogicalHeight()));
1387 context.Clip(FloatRect(box_rect)); 1457 context.Clip(FloatRect(box_rect));
1388 context.DrawHighlightForText(font, run, FloatPoint(box_origin), 1458 context.DrawHighlightForText(font, run, FloatPoint(box_origin),
1389 box_rect.Height().ToInt(), color, 1459 box_rect.Height().ToInt(), color,
1390 paint_offsets.first, paint_offsets.second); 1460 paint_offsets.first, paint_offsets.second);
1391 } 1461 }
1392 1462
1393 } // namespace blink 1463 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698