OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |