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

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: Sync to head. 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 float 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(
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) != 0);
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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 style_to_use, emphasis_mark_position); 850 style_to_use, emphasis_mark_position);
662 if (has_text_emphasis) 851 if (has_text_emphasis)
663 text_painter.SetEmphasisMark(style_to_use.TextEmphasisMarkString(), 852 text_painter.SetEmphasisMark(style_to_use.TextEmphasisMarkString(),
664 emphasis_mark_position); 853 emphasis_mark_position);
665 if (combined_text) 854 if (combined_text)
666 text_painter.SetCombinedText(combined_text); 855 text_painter.SetCombinedText(combined_text);
667 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr) 856 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr)
668 text_painter.SetEllipsisOffset(inline_text_box_.Truncation()); 857 text_painter.SetEllipsisOffset(inline_text_box_.Truncation());
669 858
670 if (!paint_selected_text_only) { 859 if (!paint_selected_text_only) {
860 // Paint text decorations except line-through.
861 DecorationInfo decoration_info;
862 bool has_line_through_decoration = false;
863 if (style_to_use.TextDecorationsInEffect() != kTextDecorationNone &&
864 inline_text_box_.Truncation() != kCFullTruncation) {
865 ComputeDecorationInfo(decoration_info, inline_text_box_, box_origin,
866 style_to_use.AppliedTextDecorations());
867 GraphicsContextStateSaver state_saver(context, false);
868 PrepareContextForDecoration(context, state_saver,
869 inline_text_box_.IsHorizontal(), text_style,
870 combined_text, box_rect);
871 PaintDecorationsExceptLineThrough(
872 text_painter, has_line_through_decoration, inline_text_box_,
873 decoration_info, paint_info, style_to_use.AppliedTextDecorations());
874 RestoreContextFromDecoration(context, combined_text, box_rect);
875 }
876
671 int start_offset = 0; 877 int start_offset = 0;
672 int end_offset = length; 878 int end_offset = length;
673 // Where the text and its flow have opposite directions then our offset into 879 // Where the text and its flow have opposite directions then our offset into
674 // the text given by |truncation| is at the start of the part that will be 880 // the text given by |truncation| is at the start of the part that will be
675 // visible. 881 // visible.
676 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr) { 882 if (inline_text_box_.Truncation() != kCNoTruncation && ltr != flow_is_ltr) {
677 start_offset = inline_text_box_.Truncation(); 883 start_offset = inline_text_box_.Truncation();
678 end_offset = text_run.length(); 884 end_offset = text_run.length();
679 } 885 }
680 886
681 if (paint_selected_text_separately && selection_start < selection_end) { 887 if (paint_selected_text_separately && selection_start < selection_end) {
682 start_offset = selection_end; 888 start_offset = selection_end;
683 end_offset = selection_start; 889 end_offset = selection_start;
684 } 890 }
685 891
686 text_painter.Paint(start_offset, end_offset, length, text_style); 892 text_painter.Paint(start_offset, end_offset, length, text_style);
893
894 // Paint line-through decoration if needed.
895 if (has_line_through_decoration) {
896 GraphicsContextStateSaver state_saver(context, false);
897 PrepareContextForDecoration(context, state_saver,
898 inline_text_box_.IsHorizontal(), text_style,
899 combined_text, box_rect);
900 PaintDecorationsOnlyLineThrough(text_painter, decoration_info, paint_info,
901 style_to_use.AppliedTextDecorations());
902 RestoreContextFromDecoration(context, combined_text, box_rect);
903 }
687 } 904 }
688 905
689 if ((paint_selected_text_only || paint_selected_text_separately) && 906 if ((paint_selected_text_only || paint_selected_text_separately) &&
690 selection_start < selection_end) { 907 selection_start < selection_end) {
691 // paint only the text that is selected 908 // paint only the text that is selected
692 text_painter.Paint(selection_start, selection_end, length, selection_style); 909 text_painter.Paint(selection_start, selection_end, length, selection_style);
693 } 910 }
694 911
695 // Paint decorations
696 if (style_to_use.TextDecorationsInEffect() != kTextDecorationNone &&
697 !paint_selected_text_only) {
698 GraphicsContextStateSaver state_saver(context, false);
699
700 TextPainter::UpdateGraphicsContext(
701 context, text_style, inline_text_box_.IsHorizontal(), state_saver);
702
703 if (combined_text)
704 context.ConcatCTM(
705 TextPainter::Rotation(box_rect, TextPainter::kClockwise));
706 PaintDecorations(text_painter, paint_info, box_origin,
707 style_to_use.AppliedTextDecorations());
708 if (combined_text)
709 context.ConcatCTM(
710 TextPainter::Rotation(box_rect, TextPainter::kCounterclockwise));
711 }
712
713 if (paint_info.phase == kPaintPhaseForeground) 912 if (paint_info.phase == kPaintPhaseForeground)
714 PaintDocumentMarkers(paint_info, box_origin, style_to_use, font, 913 PaintDocumentMarkers(paint_info, box_origin, style_to_use, font,
715 DocumentMarkerPaintPhase::kForeground); 914 DocumentMarkerPaintPhase::kForeground);
716 915
717 if (should_rotate) 916 if (should_rotate)
718 context.ConcatCTM( 917 context.ConcatCTM(
719 TextPainter::Rotation(box_rect, TextPainter::kCounterclockwise)); 918 TextPainter::Rotation(box_rect, TextPainter::kCounterclockwise));
720 } 919 }
721 920
722 bool InlineTextBoxPainter::ShouldPaintTextBox(const PaintInfo& paint_info) { 921 bool InlineTextBoxPainter::ShouldPaintTextBox(const PaintInfo& paint_info) {
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after
1099 LayoutRect& rect) { 1298 LayoutRect& rect) {
1100 FloatRectOutsets outsets = FloatRectOutsets(); 1299 FloatRectOutsets outsets = FloatRectOutsets();
1101 float space_width = inline_text_box_.NewlineSpaceWidth(); 1300 float space_width = inline_text_box_.NewlineSpaceWidth();
1102 if (inline_text_box_.IsLeftToRightDirection()) 1301 if (inline_text_box_.IsLeftToRightDirection())
1103 outsets.SetRight(space_width); 1302 outsets.SetRight(space_width);
1104 else 1303 else
1105 outsets.SetLeft(space_width); 1304 outsets.SetLeft(space_width);
1106 rect.Expand(outsets); 1305 rect.Expand(outsets);
1107 } 1306 }
1108 1307
1109 void InlineTextBoxPainter::PaintDecorations(
1110 TextPainter& text_painter,
1111 const PaintInfo& paint_info,
1112 const LayoutPoint& box_origin,
1113 const Vector<AppliedTextDecoration>& decorations) {
1114 if (inline_text_box_.Truncation() == kCFullTruncation)
1115 return;
1116
1117 GraphicsContext& context = paint_info.context;
1118 GraphicsContextStateSaver state_saver(context);
1119
1120 LayoutPoint local_origin(box_origin);
1121
1122 LayoutUnit width = inline_text_box_.LogicalWidth();
1123 if (inline_text_box_.Truncation() != kCNoTruncation) {
1124 bool ltr = inline_text_box_.IsLeftToRightDirection();
1125 bool flow_is_ltr =
1126 inline_text_box_.GetLineLayoutItem().Style()->IsLeftToRightDirection();
1127 width = LayoutUnit(inline_text_box_.GetLineLayoutItem().Width(
1128 ltr == flow_is_ltr
1129 ? inline_text_box_.Start()
1130 : inline_text_box_.Start() + inline_text_box_.Truncation(),
1131 ltr == flow_is_ltr
1132 ? inline_text_box_.Truncation()
1133 : inline_text_box_.Len() - inline_text_box_.Truncation(),
1134 inline_text_box_.TextPos(),
1135 flow_is_ltr ? TextDirection::kLtr : TextDirection::kRtl,
1136 inline_text_box_.IsFirstLineStyle()));
1137 if (!flow_is_ltr)
1138 local_origin.Move(inline_text_box_.LogicalWidth() - width, LayoutUnit());
1139 }
1140
1141 LayoutObject& text_box_layout_object = InlineLayoutObject();
1142
1143 const ComputedStyle& style_to_use =
1144 text_box_layout_object.StyleRef(inline_text_box_.IsFirstLineStyle());
1145 const SimpleFontData* font_data = style_to_use.GetFont().PrimaryFont();
1146 DCHECK(font_data);
1147 float baseline = font_data ? font_data->GetFontMetrics().FloatAscent() : 0;
1148
1149 // Set the thick of the line to be 10% (or something else ?)of the computed
1150 // font size and not less than 1px. Using computedFontSize should take care
1151 // of zoom as well.
1152
1153 // Update Underline thickness, in case we have Faulty Font Metrics calculating
1154 // underline thickness by old method.
1155 float text_decoration_thickness = 0.0;
1156 int font_height_int = 0;
1157 if (font_data) {
1158 text_decoration_thickness =
1159 font_data->GetFontMetrics().UnderlineThickness();
1160 font_height_int = (int)(font_data->GetFontMetrics().FloatHeight() + 0.5);
1161 }
1162 if ((text_decoration_thickness == 0.f) ||
1163 (text_decoration_thickness >= (font_height_int >> 1)))
1164 text_decoration_thickness =
1165 std::max(1.f, style_to_use.ComputedFontSize() / 10.f);
1166
1167 context.SetStrokeThickness(text_decoration_thickness);
1168
1169 bool antialias_decoration = ShouldSetDecorationAntialias(decorations);
1170
1171 // Offset between lines - always non-zero, so lines never cross each other.
1172 float double_offset = text_decoration_thickness + 1.f;
1173 bool skip_intercepts =
1174 style_to_use.GetTextDecorationSkip() & kTextDecorationSkipInk;
1175
1176 // text-underline-position may flip underline and overline.
1177 ResolvedUnderlinePosition underline_position =
1178 ResolveUnderlinePosition(style_to_use, &inline_text_box_);
1179 bool flip_underline_and_overline = false;
1180 if (underline_position == ResolvedUnderlinePosition::kOver) {
1181 flip_underline_and_overline = true;
1182 underline_position = ResolvedUnderlinePosition::kUnder;
1183 }
1184
1185 for (const AppliedTextDecoration& decoration : decorations) {
1186 TextDecoration lines = decoration.Lines();
1187 if (flip_underline_and_overline) {
1188 lines = static_cast<TextDecoration>(
1189 lines ^ (kTextDecorationUnderline | kTextDecorationOverline));
1190 }
1191 if ((lines & kTextDecorationUnderline) && font_data) {
1192 const int underline_offset = ComputeUnderlineOffset(
1193 underline_position, style_to_use, font_data->GetFontMetrics(),
1194 &inline_text_box_, text_decoration_thickness);
1195 AppliedDecorationPainter decoration_painter(
1196 context, FloatPoint(local_origin) + FloatPoint(0, underline_offset),
1197 width.ToFloat(), decoration, text_decoration_thickness, double_offset,
1198 1, antialias_decoration);
1199 if (skip_intercepts) {
1200 text_painter.ClipDecorationsStripe(
1201 -baseline + decoration_painter.DecorationBounds().Y() -
1202 FloatPoint(local_origin).Y(),
1203 decoration_painter.DecorationBounds().Height(),
1204 text_decoration_thickness);
1205 }
1206 decoration_painter.Paint();
1207 }
1208 if (lines & kTextDecorationOverline) {
1209 const int overline_offset =
1210 ComputeOverlineOffset(style_to_use, &inline_text_box_);
1211 AppliedDecorationPainter decoration_painter(
1212 context, FloatPoint(local_origin) + FloatPoint(0, overline_offset),
1213 width.ToFloat(), decoration, text_decoration_thickness,
1214 -double_offset, 1, antialias_decoration);
1215 if (skip_intercepts) {
1216 text_painter.ClipDecorationsStripe(
1217 -baseline + decoration_painter.DecorationBounds().Y() -
1218 FloatPoint(local_origin).Y(),
1219 decoration_painter.DecorationBounds().Height(),
1220 text_decoration_thickness);
1221 }
1222 decoration_painter.Paint();
1223 }
1224 if (lines & kTextDecorationLineThrough) {
1225 const float line_through_offset = 2 * baseline / 3;
1226 AppliedDecorationPainter decoration_painter(
1227 context,
1228 FloatPoint(local_origin) + FloatPoint(0, line_through_offset),
1229 width.ToFloat(), decoration, text_decoration_thickness, double_offset,
1230 0, antialias_decoration);
1231 // No skip: ink for line-through,
1232 // compare https://github.com/w3c/csswg-drafts/issues/711
1233 decoration_painter.Paint();
1234 }
1235 }
1236 }
1237
1238 void InlineTextBoxPainter::PaintCompositionUnderline( 1308 void InlineTextBoxPainter::PaintCompositionUnderline(
1239 GraphicsContext& context, 1309 GraphicsContext& context,
1240 const LayoutPoint& box_origin, 1310 const LayoutPoint& box_origin,
1241 const CompositionUnderline& underline) { 1311 const CompositionUnderline& underline) {
1242 if (underline.GetColor() == Color::kTransparent) 1312 if (underline.GetColor() == Color::kTransparent)
1243 return; 1313 return;
1244 1314
1245 if (inline_text_box_.Truncation() == kCFullTruncation) 1315 if (inline_text_box_.Truncation() == kCFullTruncation)
1246 return; 1316 return;
1247 1317
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1383 1453
1384 LayoutRect box_rect(box_origin, LayoutSize(inline_text_box_.LogicalWidth(), 1454 LayoutRect box_rect(box_origin, LayoutSize(inline_text_box_.LogicalWidth(),
1385 inline_text_box_.LogicalHeight())); 1455 inline_text_box_.LogicalHeight()));
1386 context.Clip(FloatRect(box_rect)); 1456 context.Clip(FloatRect(box_rect));
1387 context.DrawHighlightForText(font, run, FloatPoint(box_origin), 1457 context.DrawHighlightForText(font, run, FloatPoint(box_origin),
1388 box_rect.Height().ToInt(), color, 1458 box_rect.Height().ToInt(), color,
1389 paint_offsets.first, paint_offsets.second); 1459 paint_offsets.first, paint_offsets.second);
1390 } 1460 }
1391 1461
1392 } // namespace blink 1462 } // 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