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 float start_point_y_offset, |
wkorman
2017/04/17 17:57:59
This patch changes this to a float, which preserve
| |
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( | |
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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |