OLD | NEW |
1 /* | 1 /* |
2 * (C) 1999 Lars Knoll (knoll@kde.org) | 2 * (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 2000 Dirk Mueller (mueller@kde.org) | 3 * (C) 2000 Dirk Mueller (mueller@kde.org) |
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r
ights reserved. | 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r
ights reserved. |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
10 * | 10 * |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 return -1; | 322 return -1; |
323 } | 323 } |
324 | 324 |
325 static Color textColorForWhiteBackground(Color textColor) | 325 static Color textColorForWhiteBackground(Color textColor) |
326 { | 326 { |
327 int distanceFromWhite = differenceSquared(textColor, Color::white); | 327 int distanceFromWhite = differenceSquared(textColor, Color::white); |
328 // semi-arbitrarily chose 65025 (255^2) value here after a few tests; | 328 // semi-arbitrarily chose 65025 (255^2) value here after a few tests; |
329 return distanceFromWhite > 65025 ? textColor : textColor.dark(); | 329 return distanceFromWhite > 65025 ? textColor : textColor.dark(); |
330 } | 330 } |
331 | 331 |
332 static void updateGraphicsContext(GraphicsContext* context, const Color& fillCol
or, const Color& strokeColor, float strokeThickness) | |
333 { | |
334 TextDrawingModeFlags mode = context->textDrawingMode(); | |
335 if (strokeThickness > 0) { | |
336 TextDrawingModeFlags newMode = mode | TextModeStroke; | |
337 if (mode != newMode) { | |
338 context->setTextDrawingMode(newMode); | |
339 mode = newMode; | |
340 } | |
341 } | |
342 | |
343 if (mode & TextModeFill && fillColor != context->fillColor()) | |
344 context->setFillColor(fillColor); | |
345 | |
346 if (mode & TextModeStroke) { | |
347 if (strokeColor != context->strokeColor()) | |
348 context->setStrokeColor(strokeColor); | |
349 if (strokeThickness != context->strokeThickness()) | |
350 context->setStrokeThickness(strokeThickness); | |
351 } | |
352 } | |
353 | |
354 bool InlineTextBox::isLineBreak() const | 332 bool InlineTextBox::isLineBreak() const |
355 { | 333 { |
356 return renderer().isBR() || (renderer().style()->preserveNewline() && len()
== 1 && (*renderer().text().impl())[start()] == '\n'); | 334 return renderer().isBR() || (renderer().style()->preserveNewline() && len()
== 1 && (*renderer().text().impl())[start()] == '\n'); |
357 } | 335 } |
358 | 336 |
359 bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
sult, const HitTestLocation& locationInContainer, const LayoutPoint& accumulated
Offset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) | 337 bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
sult, const HitTestLocation& locationInContainer, const LayoutPoint& accumulated
Offset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) |
360 { | 338 { |
361 if (isLineBreak()) | 339 if (isLineBreak()) |
362 return false; | 340 return false; |
363 | 341 |
364 FloatPoint boxOrigin = locationIncludingFlipping(); | 342 FloatPoint boxOrigin = locationIncludingFlipping(); |
365 boxOrigin.moveBy(accumulatedOffset); | 343 boxOrigin.moveBy(accumulatedOffset); |
366 FloatRect rect(boxOrigin, size()); | 344 FloatRect rect(boxOrigin, size()); |
367 if (m_truncation != cFullTruncation && visibleToHitTestRequest(request) && l
ocationInContainer.intersects(rect)) { | 345 if (m_truncation != cFullTruncation && visibleToHitTestRequest(request) && l
ocationInContainer.intersects(rect)) { |
368 renderer().updateHitTestResult(result, flipForWritingMode(locationInCont
ainer.point() - toLayoutSize(accumulatedOffset))); | 346 renderer().updateHitTestResult(result, flipForWritingMode(locationInCont
ainer.point() - toLayoutSize(accumulatedOffset))); |
369 if (!result.addNodeToRectBasedTestResult(renderer().node(), request, loc
ationInContainer, rect)) | 347 if (!result.addNodeToRectBasedTestResult(renderer().node(), request, loc
ationInContainer, rect)) |
370 return true; | 348 return true; |
371 } | 349 } |
372 return false; | 350 return false; |
373 } | 351 } |
374 | 352 |
375 static void paintTextWithShadows(GraphicsContext* context, | |
376 const Font& font, const TextRun& textRun, | |
377 const AtomicString& emphasisMark, int emphasisMarkOffset, | |
378 int startOffset, int endOffset, int truncationPoint, | |
379 const FloatPoint& textOrigin, const FloatRect& boxRect, | |
380 const ShadowList* shadowList, bool horizontal) | |
381 { | |
382 // Text shadows are disabled when printing. http://crbug.com/258321 | |
383 bool hasShadow = shadowList && !context->printing(); | |
384 if (hasShadow) | |
385 context->setDrawLooper(shadowList->createDrawLooper(DrawLooperBuilder::S
hadowIgnoresAlpha, horizontal)); | |
386 | |
387 TextRunPaintInfo textRunPaintInfo(textRun); | |
388 textRunPaintInfo.bounds = boxRect; | |
389 if (startOffset <= endOffset) { | |
390 textRunPaintInfo.from = startOffset; | |
391 textRunPaintInfo.to = endOffset; | |
392 if (emphasisMark.isEmpty()) | |
393 context->drawText(font, textRunPaintInfo, textOrigin); | |
394 else | |
395 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, tex
tOrigin + IntSize(0, emphasisMarkOffset)); | |
396 } else { | |
397 if (endOffset > 0) { | |
398 textRunPaintInfo.from = 0; | |
399 textRunPaintInfo.to = endOffset; | |
400 if (emphasisMark.isEmpty()) | |
401 context->drawText(font, textRunPaintInfo, textOrigin); | |
402 else | |
403 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark,
textOrigin + IntSize(0, emphasisMarkOffset)); | |
404 } | |
405 if (startOffset < truncationPoint) { | |
406 textRunPaintInfo.from = startOffset; | |
407 textRunPaintInfo.to = truncationPoint; | |
408 if (emphasisMark.isEmpty()) | |
409 context->drawText(font, textRunPaintInfo, textOrigin); | |
410 else | |
411 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark,
textOrigin + IntSize(0, emphasisMarkOffset)); | |
412 } | |
413 } | |
414 | |
415 if (hasShadow) | |
416 context->clearDrawLooper(); | |
417 } | |
418 | |
419 static void paintEmphasisMark(GraphicsContext* context, | |
420 const AtomicString& emphasisMark, int emphasisMarkOffset, | |
421 int startOffset, int endOffset, int paintRunLength, | |
422 const Font& font, Color emphasisMarkColor, Color textStrokeColor, float text
StrokeWidth, const ShadowList* textShadow, | |
423 RenderCombineText* combinedText, const TextRun& textRun, | |
424 const FloatPoint& textOrigin, const FloatRect& boxRect, bool horizontal) | |
425 { | |
426 ASSERT(!emphasisMark.isEmpty()); | |
427 updateGraphicsContext(context, emphasisMarkColor, textStrokeColor, textStrok
eWidth); | |
428 | |
429 if (combinedText) { | |
430 DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&object
ReplacementCharacter, 1)); | |
431 FloatPoint emphasisMarkTextOrigin(boxRect.x() + boxRect.width() / 2, box
Rect.y() + font.fontMetrics().ascent()); | |
432 context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clock
wise)); | |
433 paintTextWithShadows(context, combinedText->originalFont(), objectReplac
ementCharacterTextRun, emphasisMark, emphasisMarkOffset, 0, 1, 1, emphasisMarkTe
xtOrigin, boxRect, textShadow, horizontal); | |
434 context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Count
erclockwise)); | |
435 } else { | |
436 paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkO
ffset, startOffset, endOffset, paintRunLength, textOrigin, boxRect, textShadow,
horizontal); | |
437 } | |
438 } | |
439 | |
440 bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosi
tion& emphasisPosition) const | 353 bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosi
tion& emphasisPosition) const |
441 { | 354 { |
442 // This function returns true if there are text emphasis marks and they are
suppressed by ruby text. | 355 // This function returns true if there are text emphasis marks and they are
suppressed by ruby text. |
443 if (style->textEmphasisMark() == TextEmphasisMarkNone) | 356 if (style->textEmphasisMark() == TextEmphasisMarkNone) |
444 return false; | 357 return false; |
445 | 358 |
446 emphasisPosition = style->textEmphasisPosition(); | 359 emphasisPosition = style->textEmphasisPosition(); |
447 if (emphasisPosition == TextEmphasisPositionUnder) | 360 if (emphasisPosition == TextEmphasisPositionUnder) |
448 return true; // Ruby text is always over, so it cannot suppress emphasis
marks under. | 361 return true; // Ruby text is always over, so it cannot suppress emphasis
marks under. |
449 | 362 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 } | 449 } |
537 | 450 |
538 // Text shadows are disabled when printing. http://crbug.com/258321 | 451 // Text shadows are disabled when printing. http://crbug.com/258321 |
539 if (isPrinting) | 452 if (isPrinting) |
540 selectionStyle.shadow = 0; | 453 selectionStyle.shadow = 0; |
541 } | 454 } |
542 | 455 |
543 return selectionStyle; | 456 return selectionStyle; |
544 } | 457 } |
545 | 458 |
| 459 void updateGraphicsContext(GraphicsContext* context, const TextPaintingStyle& te
xtStyle, bool horizontal, GraphicsContextStateSaver& stateSaver) |
| 460 { |
| 461 TextDrawingModeFlags mode = context->textDrawingMode(); |
| 462 if (textStyle.strokeWidth > 0) { |
| 463 TextDrawingModeFlags newMode = mode | TextModeStroke; |
| 464 if (mode != newMode) { |
| 465 if (!stateSaver.saved()) |
| 466 stateSaver.save(); |
| 467 context->setTextDrawingMode(newMode); |
| 468 mode = newMode; |
| 469 } |
| 470 } |
| 471 |
| 472 if (mode & TextModeFill && textStyle.fillColor != context->fillColor()) |
| 473 context->setFillColor(textStyle.fillColor); |
| 474 |
| 475 if (mode & TextModeStroke) { |
| 476 if (textStyle.strokeColor != context->strokeColor()) |
| 477 context->setStrokeColor(textStyle.strokeColor); |
| 478 if (textStyle.strokeWidth != context->strokeThickness()) |
| 479 context->setStrokeThickness(textStyle.strokeWidth); |
| 480 } |
| 481 |
| 482 // Text shadows are disabled when printing. http://crbug.com/258321 |
| 483 if (textStyle.shadow && !context->printing()) { |
| 484 if (!stateSaver.saved()) |
| 485 stateSaver.save(); |
| 486 context->setDrawLooper(textStyle.shadow->createDrawLooper(DrawLooperBuil
der::ShadowIgnoresAlpha, horizontal)); |
| 487 } |
| 488 } |
| 489 |
| 490 void paintText(GraphicsContext* context, |
| 491 const Font& font, const TextRun& textRun, |
| 492 const AtomicString& emphasisMark, int emphasisMarkOffset, |
| 493 int startOffset, int endOffset, int truncationPoint, |
| 494 const FloatPoint& textOrigin, const FloatRect& boxRect) |
| 495 { |
| 496 TextRunPaintInfo textRunPaintInfo(textRun); |
| 497 textRunPaintInfo.bounds = boxRect; |
| 498 if (startOffset <= endOffset) { |
| 499 textRunPaintInfo.from = startOffset; |
| 500 textRunPaintInfo.to = endOffset; |
| 501 if (emphasisMark.isEmpty()) |
| 502 context->drawText(font, textRunPaintInfo, textOrigin); |
| 503 else |
| 504 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, tex
tOrigin + IntSize(0, emphasisMarkOffset)); |
| 505 } else { |
| 506 if (endOffset > 0) { |
| 507 textRunPaintInfo.from = 0; |
| 508 textRunPaintInfo.to = endOffset; |
| 509 if (emphasisMark.isEmpty()) |
| 510 context->drawText(font, textRunPaintInfo, textOrigin); |
| 511 else |
| 512 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark,
textOrigin + IntSize(0, emphasisMarkOffset)); |
| 513 } |
| 514 if (startOffset < truncationPoint) { |
| 515 textRunPaintInfo.from = startOffset; |
| 516 textRunPaintInfo.to = truncationPoint; |
| 517 if (emphasisMark.isEmpty()) |
| 518 context->drawText(font, textRunPaintInfo, textOrigin); |
| 519 else |
| 520 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark,
textOrigin + IntSize(0, emphasisMarkOffset)); |
| 521 } |
| 522 } |
| 523 } |
| 524 |
| 525 inline void paintEmphasisMark(GraphicsContext* context, |
| 526 const AtomicString& emphasisMark, int emphasisMarkOffset, |
| 527 int startOffset, int endOffset, int paintRunLength, |
| 528 const Font& font, RenderCombineText* combinedText, const TextRun& textRun, |
| 529 const FloatPoint& textOrigin, const FloatRect& boxRect) |
| 530 { |
| 531 ASSERT(!emphasisMark.isEmpty()); |
| 532 |
| 533 if (combinedText) { |
| 534 DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&object
ReplacementCharacter, 1)); |
| 535 FloatPoint emphasisMarkTextOrigin(boxRect.x() + boxRect.width() / 2, box
Rect.y() + font.fontMetrics().ascent()); |
| 536 context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clock
wise)); |
| 537 paintText(context, combinedText->originalFont(), objectReplacementCharac
terTextRun, emphasisMark, emphasisMarkOffset, 0, 1, 1, emphasisMarkTextOrigin, b
oxRect); |
| 538 context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Count
erclockwise)); |
| 539 } else { |
| 540 paintText(context, font, textRun, emphasisMark, emphasisMarkOffset, star
tOffset, endOffset, paintRunLength, textOrigin, boxRect); |
| 541 } |
| 542 } |
| 543 |
| 544 void paintTextWithEmphasisMark( |
| 545 GraphicsContext* context, const Font& font, const TextPaintingStyle& textSty
le, const TextRun& textRun, |
| 546 const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, i
nt endOffset, int length, |
| 547 RenderCombineText* combinedText, const FloatPoint& textOrigin, const FloatRe
ct& boxRect, bool horizontal) |
| 548 { |
| 549 GraphicsContextStateSaver stateSaver(*context, false); |
| 550 updateGraphicsContext(context, textStyle, horizontal, stateSaver); |
| 551 paintText(context, font, textRun, nullAtom, 0, startOffset, endOffset, lengt
h, textOrigin, boxRect); |
| 552 |
| 553 if (!emphasisMark.isEmpty()) { |
| 554 if (textStyle.emphasisMarkColor != textStyle.fillColor) |
| 555 context->setFillColor(textStyle.emphasisMarkColor); |
| 556 paintEmphasisMark(context, emphasisMark, emphasisMarkOffset, startOffset
, endOffset, length, font, combinedText, textRun, textOrigin, boxRect); |
| 557 } |
| 558 } |
| 559 |
546 } // namespace | 560 } // namespace |
547 | 561 |
548 void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
LayoutUnit /*lineTop*/, LayoutUnit /*lineBottom*/) | 562 void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
LayoutUnit /*lineTop*/, LayoutUnit /*lineBottom*/) |
549 { | 563 { |
550 if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(&renderer()) || render
er().style()->visibility() != VISIBLE | 564 if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(&renderer()) || render
er().style()->visibility() != VISIBLE |
551 || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutli
ne || !m_len) | 565 || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutli
ne || !m_len) |
552 return; | 566 return; |
553 | 567 |
554 ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintP
haseChildOutlines); | 568 ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintP
haseChildOutlines); |
555 | 569 |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 emphasisMarkOffset = emphasisMarkPosition == TextEmphasisPositionOver ?
-font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fon
tMetrics().descent() + font.emphasisMarkAscent(emphasisMark); | 694 emphasisMarkOffset = emphasisMarkPosition == TextEmphasisPositionOver ?
-font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fon
tMetrics().descent() + font.emphasisMarkAscent(emphasisMark); |
681 | 695 |
682 if (!paintSelectedTextOnly) { | 696 if (!paintSelectedTextOnly) { |
683 // FIXME: Truncate right-to-left text correctly. | 697 // FIXME: Truncate right-to-left text correctly. |
684 int startOffset = 0; | 698 int startOffset = 0; |
685 int endOffset = length; | 699 int endOffset = length; |
686 if (paintSelectedTextSeparately && ePos > sPos) { | 700 if (paintSelectedTextSeparately && ePos > sPos) { |
687 startOffset = ePos; | 701 startOffset = ePos; |
688 endOffset = sPos; | 702 endOffset = sPos; |
689 } | 703 } |
690 | 704 paintTextWithEmphasisMark(context, font, textStyle, textRun, emphasisMar
k, emphasisMarkOffset, startOffset, endOffset, length, combinedText, textOrigin,
boxRect, isHorizontal()); |
691 // For stroked painting, we have to change the text drawing mode. It's
probably dangerous to leave that mutated as a side | |
692 // effect, so only when we know we're stroking, do a save/restore. | |
693 GraphicsContextStateSaver stateSaver(*context, textStyle.strokeWidth > 0
); | |
694 | |
695 updateGraphicsContext(context, textStyle.fillColor, textStyle.strokeColo
r, textStyle.strokeWidth); | |
696 paintTextWithShadows(context, font, textRun, nullAtom, 0, startOffset, e
ndOffset, length, textOrigin, boxRect, textStyle.shadow, isHorizontal()); | |
697 | |
698 if (!emphasisMark.isEmpty()) | |
699 paintEmphasisMark(context, emphasisMark, emphasisMarkOffset, startOf
fset, endOffset, length, font, textStyle.emphasisMarkColor, textStyle.strokeColo
r, textStyle.strokeWidth, textStyle.shadow, combinedText, textRun, textOrigin, b
oxRect, isHorizontal()); | |
700 } | 705 } |
701 | 706 |
702 if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) { | 707 if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) { |
703 // paint only the text that is selected | 708 // paint only the text that is selected |
704 GraphicsContextStateSaver stateSaver(*context, selectionStyle.strokeWidt
h > 0); | 709 paintTextWithEmphasisMark(context, font, selectionStyle, textRun, emphas
isMark, emphasisMarkOffset, sPos, ePos, length, combinedText, textOrigin, boxRec
t, isHorizontal()); |
705 | |
706 updateGraphicsContext(context, selectionStyle.fillColor, selectionStyle.
strokeColor, selectionStyle.strokeWidth); | |
707 paintTextWithShadows(context, font, textRun, nullAtom, 0, sPos, ePos, le
ngth, textOrigin, boxRect, selectionStyle.shadow, isHorizontal()); | |
708 | |
709 if (!emphasisMark.isEmpty()) | |
710 paintEmphasisMark(context, emphasisMark, emphasisMarkOffset, sPos, e
Pos, length, font, selectionStyle.emphasisMarkColor, selectionStyle.strokeColor,
textStyle.strokeWidth, selectionStyle.shadow, combinedText, textRun, textOrigin
, boxRect, isHorizontal()); | |
711 } | 710 } |
712 | 711 |
713 // Paint decorations | 712 // Paint decorations |
714 TextDecoration textDecorations = styleToUse->textDecorationsInEffect(); | 713 TextDecoration textDecorations = styleToUse->textDecorationsInEffect(); |
715 if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSe
lection) { | 714 if (textDecorations != TextDecorationNone && !paintSelectedTextOnly) { |
716 updateGraphicsContext(context, textStyle.fillColor, textStyle.strokeColo
r, textStyle.strokeWidth); | 715 GraphicsContextStateSaver stateSaver(*context, false); |
| 716 updateGraphicsContext(context, textStyle, isHorizontal(), stateSaver); |
717 if (combinedText) | 717 if (combinedText) |
718 context->concatCTM(rotation(boxRect, Clockwise)); | 718 context->concatCTM(rotation(boxRect, Clockwise)); |
719 paintDecoration(context, boxOrigin, textDecorations, textStyle.shadow); | 719 paintDecoration(context, boxOrigin, textDecorations); |
720 if (combinedText) | 720 if (combinedText) |
721 context->concatCTM(rotation(boxRect, Counterclockwise)); | 721 context->concatCTM(rotation(boxRect, Counterclockwise)); |
722 } | 722 } |
723 | 723 |
724 if (paintInfo.phase == PaintPhaseForeground) { | 724 if (paintInfo.phase == PaintPhaseForeground) { |
725 paintDocumentMarkers(context, boxOrigin, styleToUse, font, false); | 725 paintDocumentMarkers(context, boxOrigin, styleToUse, font, false); |
726 | 726 |
727 // Paint custom underlines for compositions. | 727 // Paint custom underlines for compositions. |
728 if (useCustomUnderlines) { | 728 if (useCustomUnderlines) { |
729 const Vector<CompositionUnderline>& underlines = renderer().frame()-
>inputMethodController().customCompositionUnderlines(); | 729 const Vector<CompositionUnderline>& underlines = renderer().frame()-
>inputMethodController().customCompositionUnderlines(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
768 | 768 |
769 Color c = renderer().selectionBackgroundColor(); | 769 Color c = renderer().selectionBackgroundColor(); |
770 if (!c.alpha()) | 770 if (!c.alpha()) |
771 return; | 771 return; |
772 | 772 |
773 // If the text color ends up being the same as the selection background, inv
ert the selection | 773 // If the text color ends up being the same as the selection background, inv
ert the selection |
774 // background. | 774 // background. |
775 if (textColor == c) | 775 if (textColor == c) |
776 c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); | 776 c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); |
777 | 777 |
778 | |
779 // If the text is truncated, let the thing being painted in the truncation | 778 // If the text is truncated, let the thing being painted in the truncation |
780 // draw its own highlight. | 779 // draw its own highlight. |
781 int length = m_truncation != cNoTruncation ? m_truncation : m_len; | 780 int length = m_truncation != cNoTruncation ? m_truncation : m_len; |
782 StringView string = renderer().text().createView(); | 781 StringView string = renderer().text().createView(); |
783 | 782 |
784 if (string.length() != static_cast<unsigned>(length) || m_start) | 783 if (string.length() != static_cast<unsigned>(length) || m_start) |
785 string.narrow(m_start, length); | 784 string.narrow(m_start, length); |
786 | 785 |
787 StringBuilder charactersWithHyphen; | 786 StringBuilder charactersWithHyphen; |
788 bool respectHyphen = ePos == length && hasHyphen(); | 787 bool respectHyphen = ePos == length && hasHyphen(); |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 context->setShouldAntialias(antialiasDecoration); | 1034 context->setShouldAntialias(antialiasDecoration); |
1036 // Fall through | 1035 // Fall through |
1037 default: | 1036 default: |
1038 context->drawLineForText(start, width, isPrinting); | 1037 context->drawLineForText(start, width, isPrinting); |
1039 | 1038 |
1040 if (decoration.style == TextDecorationStyleDouble) | 1039 if (decoration.style == TextDecorationStyleDouble) |
1041 context->drawLineForText(start + FloatPoint(0, doubleOffset), width,
isPrinting); | 1040 context->drawLineForText(start + FloatPoint(0, doubleOffset), width,
isPrinting); |
1042 } | 1041 } |
1043 } | 1042 } |
1044 | 1043 |
1045 void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
boxOrigin, TextDecoration deco, const ShadowList* shadowList) | 1044 void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint&
boxOrigin, TextDecoration deco) |
1046 { | 1045 { |
1047 GraphicsContextStateSaver stateSaver(*context); | 1046 GraphicsContextStateSaver stateSaver(*context); |
1048 | 1047 |
1049 if (m_truncation == cFullTruncation) | 1048 if (m_truncation == cFullTruncation) |
1050 return; | 1049 return; |
1051 | 1050 |
1052 FloatPoint localOrigin = boxOrigin; | 1051 FloatPoint localOrigin = boxOrigin; |
1053 | 1052 |
1054 float width = m_logicalWidth; | 1053 float width = m_logicalWidth; |
1055 if (m_truncation != cNoTruncation) { | 1054 if (m_truncation != cNoTruncation) { |
1056 width = renderer().width(m_start, m_truncation, textPos(), isLeftToRight
Direction() ? LTR : RTL, isFirstLineStyle()); | 1055 width = renderer().width(m_start, m_truncation, textPos(), isLeftToRight
Direction() ? LTR : RTL, isFirstLineStyle()); |
1057 if (!isLeftToRightDirection()) | 1056 if (!isLeftToRightDirection()) |
1058 localOrigin.move(m_logicalWidth - width, 0); | 1057 localOrigin.move(m_logicalWidth - width, 0); |
1059 } | 1058 } |
1060 | 1059 |
1061 // Get the text decoration colors. | 1060 // Get the text decoration colors. |
1062 RenderObject::AppliedTextDecoration underline, overline, linethrough; | 1061 RenderObject::AppliedTextDecoration underline, overline, linethrough; |
1063 | |
1064 renderer().getTextDecorations(deco, underline, overline, linethrough, true); | 1062 renderer().getTextDecorations(deco, underline, overline, linethrough, true); |
1065 if (isFirstLineStyle()) | 1063 if (isFirstLineStyle()) |
1066 renderer().getTextDecorations(deco, underline, overline, linethrough, tr
ue, true); | 1064 renderer().getTextDecorations(deco, underline, overline, linethrough, tr
ue, true); |
1067 | 1065 |
1068 // Use a special function for underlines to get the positioning exactly righ
t. | 1066 // Use a special function for underlines to get the positioning exactly righ
t. |
1069 bool isPrinting = renderer().document().printing(); | 1067 bool isPrinting = renderer().document().printing(); |
1070 | 1068 |
1071 bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || u
nderline.color.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.
color.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.col
or.alpha() == 255); | |
1072 | |
1073 RenderStyle* styleToUse = renderer().style(isFirstLineStyle()); | 1069 RenderStyle* styleToUse = renderer().style(isFirstLineStyle()); |
1074 int baseline = styleToUse->fontMetrics().ascent(); | 1070 int baseline = styleToUse->fontMetrics().ascent(); |
1075 | 1071 |
1076 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0; | |
1077 // Set the thick of the line to be 10% (or something else ?)of the computed
font size and not less than 1px. | 1072 // Set the thick of the line to be 10% (or something else ?)of the computed
font size and not less than 1px. |
1078 // Using computedFontSize should take care of zoom as well. | 1073 // Using computedFontSize should take care of zoom as well. |
1079 | 1074 |
1080 // Update Underline thickness, in case we have Faulty Font Metrics calculati
ng underline thickness by old method. | 1075 // Update Underline thickness, in case we have Faulty Font Metrics calculati
ng underline thickness by old method. |
1081 float textDecorationThickness = styleToUse->fontMetrics().underlineThickness
(); | 1076 float textDecorationThickness = styleToUse->fontMetrics().underlineThickness
(); |
1082 int fontHeightInt = (int)(styleToUse->fontMetrics().floatHeight() + 0.5); | 1077 int fontHeightInt = (int)(styleToUse->fontMetrics().floatHeight() + 0.5); |
1083 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHei
ghtInt >> 1))) | 1078 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHei
ghtInt >> 1))) |
1084 textDecorationThickness = std::max(1.f, styleToUse->computedFontSize() /
10.f); | 1079 textDecorationThickness = std::max(1.f, styleToUse->computedFontSize() /
10.f); |
1085 | 1080 |
1086 context->setStrokeThickness(textDecorationThickness); | 1081 context->setStrokeThickness(textDecorationThickness); |
1087 | 1082 |
1088 bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, unde
rline.style, linethrough.style) | 1083 bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, unde
rline.style, linethrough.style) |
1089 && RenderBoxModelObject::shouldAntialiasLines(context); | 1084 && RenderBoxModelObject::shouldAntialiasLines(context); |
1090 | 1085 |
1091 float extraOffset = 0; | 1086 // Offset between lines - always non-zero, so lines never cross each other. |
1092 if (!linesAreOpaque && shadowCount > 1) { | 1087 float doubleOffset = textDecorationThickness + 1.f; |
1093 FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2)); | 1088 |
1094 for (size_t i = shadowCount; i--; ) { | 1089 if (deco & TextDecorationUnderline) { |
1095 const ShadowData& s = shadowList->shadows()[i]; | 1090 const int underlineOffset = computeUnderlineOffset(styleToUse->textUnder
linePosition(), styleToUse->fontMetrics(), this, textDecorationThickness); |
1096 FloatRect shadowRect(localOrigin, FloatSize(width, baseline + 2)); | 1091 paintAppliedDecoration(context, localOrigin + FloatPoint(0, underlineOff
set), width, doubleOffset, 1, underline, textDecorationThickness, antialiasDecor
ation, isPrinting); |
1097 shadowRect.inflate(s.blur()); | |
1098 float shadowX = isHorizontal() ? s.x() : s.y(); | |
1099 float shadowY = isHorizontal() ? s.y() : -s.x(); | |
1100 shadowRect.move(shadowX, shadowY); | |
1101 clipRect.unite(shadowRect); | |
1102 extraOffset = std::max(extraOffset, std::max(0.0f, shadowY) + s.blur
()); | |
1103 } | |
1104 context->clip(clipRect); | |
1105 extraOffset += baseline + 2; | |
1106 localOrigin.move(0, extraOffset); | |
1107 } | 1092 } |
1108 | 1093 if (deco & TextDecorationOverline) { |
1109 for (size_t i = std::max(static_cast<size_t>(1), shadowCount); i--; ) { | 1094 paintAppliedDecoration(context, localOrigin, width, -doubleOffset, 1, ov
erline, textDecorationThickness, antialiasDecoration, isPrinting); |
1110 // Even if we have no shadows, we still want to run the code below this
once. | 1095 } |
1111 if (i < shadowCount) { | 1096 if (deco & TextDecorationLineThrough) { |
1112 if (!i) { | 1097 const float lineThroughOffset = 2 * baseline / 3; |
1113 // The last set of lines paints normally inside the clip. | 1098 paintAppliedDecoration(context, localOrigin + FloatPoint(0, lineThroughO
ffset), width, doubleOffset, 0, linethrough, textDecorationThickness, antialiasD
ecoration, isPrinting); |
1114 localOrigin.move(0, -extraOffset); | |
1115 extraOffset = 0; | |
1116 } | |
1117 const ShadowData& shadow = shadowList->shadows()[i]; | |
1118 float shadowX = isHorizontal() ? shadow.x() : shadow.y(); | |
1119 float shadowY = isHorizontal() ? shadow.y() : -shadow.x(); | |
1120 context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow
.blur(), shadow.color()); | |
1121 } | |
1122 | |
1123 // Offset between lines - always non-zero, so lines never cross each oth
er. | |
1124 float doubleOffset = textDecorationThickness + 1.f; | |
1125 | |
1126 if (deco & TextDecorationUnderline) { | |
1127 const int underlineOffset = computeUnderlineOffset(styleToUse->textU
nderlinePosition(), styleToUse->fontMetrics(), this, textDecorationThickness); | |
1128 paintAppliedDecoration(context, localOrigin + FloatPoint(0, underlin
eOffset), width, doubleOffset, 1, underline, textDecorationThickness, antialiasD
ecoration, isPrinting); | |
1129 } | |
1130 if (deco & TextDecorationOverline) { | |
1131 paintAppliedDecoration(context, localOrigin, width, -doubleOffset, 1
, overline, textDecorationThickness, antialiasDecoration, isPrinting); | |
1132 } | |
1133 if (deco & TextDecorationLineThrough) { | |
1134 const float lineThroughOffset = 2 * baseline / 3; | |
1135 paintAppliedDecoration(context, localOrigin + FloatPoint(0, lineThro
ughOffset), width, doubleOffset, 0, linethrough, textDecorationThickness, antial
iasDecoration, isPrinting); | |
1136 } | |
1137 } | 1099 } |
1138 } | 1100 } |
1139 | 1101 |
1140 static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentM
arker::MarkerType markerType) | 1102 static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentM
arker::MarkerType markerType) |
1141 { | 1103 { |
1142 switch (markerType) { | 1104 switch (markerType) { |
1143 case DocumentMarker::Spelling: | 1105 case DocumentMarker::Spelling: |
1144 return GraphicsContext::DocumentMarkerSpellingLineStyle; | 1106 return GraphicsContext::DocumentMarkerSpellingLineStyle; |
1145 case DocumentMarker::Grammar: | 1107 case DocumentMarker::Grammar: |
1146 return GraphicsContext::DocumentMarkerGrammarLineStyle; | 1108 return GraphicsContext::DocumentMarkerGrammarLineStyle; |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1520 printedCharacters = fprintf(stderr, "\t%s %p", obj.renderName(), &obj); | 1482 printedCharacters = fprintf(stderr, "\t%s %p", obj.renderName(), &obj); |
1521 const int rendererCharacterOffset = 24; | 1483 const int rendererCharacterOffset = 24; |
1522 for (; printedCharacters < rendererCharacterOffset; printedCharacters++) | 1484 for (; printedCharacters < rendererCharacterOffset; printedCharacters++) |
1523 fputc(' ', stderr); | 1485 fputc(' ', stderr); |
1524 fprintf(stderr, "(%d,%d) \"%s\"\n", start(), start() + len(), value.utf8().d
ata()); | 1486 fprintf(stderr, "(%d,%d) \"%s\"\n", start(), start() + len(), value.utf8().d
ata()); |
1525 } | 1487 } |
1526 | 1488 |
1527 #endif | 1489 #endif |
1528 | 1490 |
1529 } // namespace blink | 1491 } // namespace blink |
OLD | NEW |