15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (C) 1999 Lars Knoll (knoll@kde.org)
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (C) 2000 Dirk Mueller (mueller@kde.org)
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Library General Public
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2 of the License, or (at your option) any later version.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful,
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Library General Public License for more details.
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Library General Public License
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * along with this library; see the file COPYING.LIB.  If not, write to
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Boston, MA 02110-1301, USA.
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
2453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/InlineTextBox.h"
2553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
2653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Document.h"
2753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/DocumentMarkerController.h"
2853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/RenderedDocumentMarker.h"
2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Text.h"
3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/Editor.h"
31e6d4491e48613634a83c1957c72759da80987961Ben Murdoch#include "core/editing/InputMethodController.h"
3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/Frame.h"
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/Page.h"
3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/page/Settings.h"
3593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "core/platform/graphics/DrawLooper.h"
3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/graphics/FontCache.h"
3781a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)#include "core/platform/graphics/GraphicsContextStateSaver.h"
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/EllipsisBox.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/HitTestResult.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/PaintInfo.h"
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderBR.h"
4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderBlock.h"
4353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderCombineText.h"
4453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderRubyRun.h"
4553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderRubyText.h"
4653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderTheme.h"
4793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "core/rendering/style/ShadowData.h"
4853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/SVGTextRunRenderingContext.h"
4993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "wtf/Vector.h"
5093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "wtf/text/CString.h"
51e6d4491e48613634a83c1957c72759da80987961Ben Murdoch#include "wtf/text/StringBuilder.h"
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace std;
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)struct SameSizeAsInlineTextBox : public InlineBox {
5893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    unsigned variables[1];
5993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    unsigned short variables2[2];
6093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    void* pointers[2];
6193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)};
6293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)COMPILE_ASSERT(sizeof(InlineTextBox) == sizeof(SameSizeAsInlineTextBox), InlineTextBox_should_stay_small);
6493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)typedef WTF::HashMap<const InlineTextBox*, LayoutRect> InlineTextBoxOverflowMap;
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static InlineTextBoxOverflowMap* gTextBoxesWithOverflow;
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
68e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)static const int misspellingLineThickness = 3;
69e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)
70f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)void InlineTextBox::destroy()
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!knownToHaveNoOverflow() && gTextBoxesWithOverflow)
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        gTextBoxesWithOverflow->remove(this);
74f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)    InlineBox::destroy();
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::markDirty(bool dirty)
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (dirty) {
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_len = 0;
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_start = 0;
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    InlineBox::markDirty(dirty);
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutRect InlineTextBox::logicalOverflowRect() const
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (knownToHaveNoOverflow() || !gTextBoxesWithOverflow)
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return enclosingIntRect(logicalFrameRect());
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return gTextBoxesWithOverflow->get(this);
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::setLogicalOverflowRect(const LayoutRect& rect)
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(!knownToHaveNoOverflow());
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!gTextBoxesWithOverflow)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        gTextBoxesWithOverflow = new InlineTextBoxOverflowMap;
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    gTextBoxesWithOverflow->add(this, rect);
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int InlineTextBox::baselinePosition(FontBaseline baselineType) const
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isText() || !parent())
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (parent()->renderer() == renderer()->parent())
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return parent()->baselinePosition(baselineType);
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return toRenderBoxModelObject(renderer()->parent())->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutUnit InlineTextBox::lineHeight() const
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isText() || !renderer()->parent())
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_renderer->isBR())
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return toRenderBR(m_renderer)->lineHeight(isFirstLineStyle());
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (parent()->renderer() == renderer()->parent())
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return parent()->lineHeight();
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return toRenderBoxModelObject(renderer()->parent())->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutUnit InlineTextBox::selectionTop()
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return root()->selectionTop();
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutUnit InlineTextBox::selectionBottom()
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return root()->selectionBottom();
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutUnit InlineTextBox::selectionHeight()
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return root()->selectionHeight();
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool InlineTextBox::isSelected(int startPos, int endPos) const
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    int sPos = max(startPos - m_start, 0);
13953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // The position after a hard line break is considered to be past its end.
14053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // See the corresponding code in InlineTextBox::selectionState.
14153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    int ePos = min(endPos - m_start, int(m_len) + (isLineBreak() ? 0 : 1));
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return (sPos < ePos);
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RenderObject::SelectionState InlineTextBox::selectionState()
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderObject::SelectionState state = renderer()->selectionState();
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || state == RenderObject::SelectionBoth) {
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int startPos, endPos;
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        renderer()->selectionStartEnd(startPos, endPos);
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // The position after a hard line break is considered to be past its end.
15253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        // See the corresponding code in InlineTextBox::isSelected.
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int lastSelectable = start() + len() - (isLineBreak() ? 1 : 0);
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        // FIXME: Remove -webkit-line-break: LineBreakAfterWhiteSpace.
15653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        int endOfLineAdjustmentForCSSLineBreak = renderer()->style()->lineBreak() == LineBreakAfterWhiteSpace ? -1 : 0;
15753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        bool start = (state != RenderObject::SelectionEnd && startPos >= m_start && startPos <= m_start + m_len + endOfLineAdjustmentForCSSLineBreak);
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool end = (state != RenderObject::SelectionStart && endPos > m_start && endPos <= lastSelectable);
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (start && end)
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = RenderObject::SelectionBoth;
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else if (start)
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = RenderObject::SelectionStart;
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else if (end)
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = RenderObject::SelectionEnd;
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else if ((state == RenderObject::SelectionEnd || startPos < m_start) &&
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                 (state == RenderObject::SelectionStart || endPos > lastSelectable))
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = RenderObject::SelectionInside;
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else if (state == RenderObject::SelectionBoth)
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = RenderObject::SelectionNone;
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If there are ellipsis following, make sure their selection is updated.
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation != cNoTruncation && root()->ellipsisBox()) {
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        EllipsisBox* ellipsis = root()->ellipsisBox();
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (state != RenderObject::SelectionNone) {
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            int start, end;
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            selectionStartEnd(start, end);
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // The ellipsis should be considered to be selected if the end of
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // the selection is past the beginning of the truncation and the
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // beginning of the selection is before or at the beginning of the
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // truncation.
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ellipsis->setSelectionState(end >= m_truncation && start <= m_truncation ?
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                RenderObject::SelectionInside : RenderObject::SelectionNone);
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        } else
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ellipsis->setSelectionState(RenderObject::SelectionNone);
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return state;
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos)
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int sPos = max(startPos - m_start, 0);
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int ePos = min(endPos - m_start, (int)m_len);
19502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (sPos > ePos)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return LayoutRect();
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FontCachePurgePreventer fontCachePurgePreventer;
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderText* textObj = textRenderer();
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit selTop = selectionTop();
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit selHeight = selectionHeight();
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderStyle* styleToUse = textObj->style(isFirstLineStyle());
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const Font& font = styleToUse->font();
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
207e6d4491e48613634a83c1957c72759da80987961Ben Murdoch    StringBuilder charactersWithHyphen;
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool respectHyphen = ePos == m_len && hasHyphen();
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TextRun textRun = constructTextRun(styleToUse, font, respectHyphen ? &charactersWithHyphen : 0);
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (respectHyphen)
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        endPos = textRun.length();
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
21353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    FloatPoint startingPoint = FloatPoint(logicalLeft(), selTop);
21453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    LayoutRect r;
21553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if (sPos || ePos != static_cast<int>(m_len))
21653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        r = enclosingIntRect(font.selectionRectForText(textRun, startingPoint, selHeight, sPos, ePos));
21753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    else // Avoid computing the font width when the entire line box is selected as an optimization.
21853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        r = enclosingIntRect(FloatRect(startingPoint, FloatSize(m_logicalWidth, selHeight)));
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit logicalWidth = r.width();
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (r.x() > logicalRight())
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logicalWidth  = 0;
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    else if (r.maxX() > logicalRight())
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        logicalWidth = logicalRight() - r.x();
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutPoint topPoint = isHorizontal() ? LayoutPoint(r.x(), selTop) : LayoutPoint(selTop, r.x());
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit width = isHorizontal() ? logicalWidth : selHeight;
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit height = isHorizontal() ? selHeight : logicalWidth;
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return LayoutRect(topPoint, LayoutSize(width, height));
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
233f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)void InlineTextBox::deleteLine()
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    toRenderText(renderer())->removeTextBox(this);
236f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)    destroy();
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::extractLine()
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (extracted())
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    toRenderText(renderer())->extractTextBox(this);
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::attachLine()
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!extracted())
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
25102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    toRenderText(renderer())->attachTextBox(this);
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float InlineTextBox::placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox)
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (foundBox) {
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_truncation = cFullTruncation;
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return -1;
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // For LTR this is the left edge of the box, for RTL, the right edge in parent coordinates.
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float ellipsisX = flowIsLTR ? visibleRightEdge - ellipsisWidth : visibleLeftEdge + ellipsisWidth;
26402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Criteria for full truncation:
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // LTR: the left edge of the ellipsis is to the left of our text run.
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // RTL: the right edge of the ellipsis is to the right of our text run.
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool ltrFullTruncation = flowIsLTR && ellipsisX <= left();
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool rtlFullTruncation = !flowIsLTR && ellipsisX >= left() + logicalWidth();
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (ltrFullTruncation || rtlFullTruncation) {
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Too far.  Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box.
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_truncation = cFullTruncation;
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        foundBox = true;
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return -1;
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool ltrEllipsisWithinBox = flowIsLTR && (ellipsisX < right());
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool rtlEllipsisWithinBox = !flowIsLTR && (ellipsisX > left());
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (ltrEllipsisWithinBox || rtlEllipsisWithinBox) {
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        foundBox = true;
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // The inline box may have different directionality than it's parent.  Since truncation
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // behavior depends both on both the parent and the inline block's directionality, we
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // must keep track of these separately.
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool ltr = isLeftToRightDirection();
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (ltr != flowIsLTR) {
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          // Width in pixels of the visible portion of the box, excluding the ellipsis.
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          int visibleBoxWidth = visibleRightEdge - visibleLeftEdge  - ellipsisWidth;
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          ellipsisX = ltr ? left() + visibleBoxWidth : right() - visibleBoxWidth;
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int offset = offsetForPosition(ellipsisX, false);
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (offset == 0) {
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // No characters should be rendered.  Set ourselves to full truncation and place the ellipsis at the min of our start
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // and the ellipsis edge.
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            m_truncation = cFullTruncation;
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            truncatedWidth += ellipsisWidth;
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return min(ellipsisX, x());
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Set the truncation index on the text run.
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_truncation = offset;
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // If we got here that means that we were only partially truncated and we need to return the pixel offset at which
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // to place the ellipsis.
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        float widthOfVisibleText = toRenderText(renderer())->width(m_start, offset, textPos(), isFirstLineStyle());
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // The ellipsis needs to be placed just after the last visible character.
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Where "after" is defined by the flow directionality, not the inline
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // box directionality.
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // e.g. In the case of an LTR inline box truncated in an RTL flow then we can
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // have a situation such as |Hello| -> |...He|
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        truncatedWidth += widthOfVisibleText + ellipsisWidth;
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (flowIsLTR)
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return left() + widthOfVisibleText;
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return right() - widthOfVisibleText - ellipsisWidth;
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    truncatedWidth += logicalWidth();
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return -1;
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
32302772c6a72f1ee0b226341a4f4439970c29fc861Ben MurdochColor correctedTextColor(Color textColor, Color backgroundColor)
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Adjust the text color if it is too close to the background color,
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // by darkening or lightening it to move it further away.
32702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int d = differenceSquared(textColor, backgroundColor);
32902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    // semi-arbitrarily chose 65025 (255^2) value here after a few tests;
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (d > 65025) {
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return textColor;
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
33302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int distanceFromWhite = differenceSquared(textColor, Color::white);
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int distanceFromBlack = differenceSquared(textColor, Color::black);
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (distanceFromWhite < distanceFromBlack) {
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return textColor.dark();
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
34002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return textColor.light();
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3445267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness)
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TextDrawingModeFlags mode = context->textDrawingMode();
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (strokeThickness > 0) {
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        TextDrawingModeFlags newMode = mode | TextModeStroke;
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (mode != newMode) {
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            context->setTextDrawingMode(newMode);
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            mode = newMode;
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3545267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
3555267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    if (mode & TextModeFill && fillColor != context->fillColor())
3565267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        context->setFillColor(fillColor);
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (mode & TextModeStroke) {
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (strokeColor != context->strokeColor())
3605267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            context->setStrokeColor(strokeColor);
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (strokeThickness != context->strokeThickness())
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            context->setStrokeThickness(strokeThickness);
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool InlineTextBox::isLineBreak() const
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
368e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch    return renderer()->isBR() || (renderer()->style()->preserveNewline() && len() == 1 && (*textRenderer()->text().impl())[start()] == '\n');
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isLineBreak())
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint boxOrigin = locationIncludingFlipping();
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    boxOrigin.moveBy(accumulatedOffset);
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatRect rect(boxOrigin, size());
37953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if (m_truncation != cFullTruncation && visibleToHitTestRequest(request) && locationInContainer.intersects(rect)) {
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset)));
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect))
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return true;
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochstatic void paintTextWithShadows(GraphicsContext* context,
3887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    const RenderObject* renderer, const Font& font, const TextRun& textRun,
3897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    const AtomicString& emphasisMark, int emphasisMarkOffset,
3907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    int startOffset, int endOffset, int truncationPoint,
3917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    const FloatPoint& textOrigin, const FloatRect& boxRect,
3927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    const ShadowData* shadow, bool stroked, bool horizontal)
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    // Text shadows are disabled when printing. http://crbug.com/258321
3957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    bool hasShadow = shadow && !context->printing();
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color fillColor = context->fillColor();
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
39893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (hasShadow) {
39993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        DrawLooper drawLooper;
40093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        do {
40193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            int shadowX = horizontal ? shadow->x() : shadow->y();
40293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            int shadowY = horizontal ? shadow->y() : -shadow->x();
40393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            FloatSize offset(shadowX, shadowY);
40483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch            drawLooper.addShadow(offset, shadow->blur(),
40583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch                renderer->resolveColor(shadow->color(), Color::stdShadowColor),
40693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha);
40793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        } while ((shadow = shadow->next()));
40893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        drawLooper.addUnmodifiedContent();
40993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        context->setDrawLooper(drawLooper);
41093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
41293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    TextRunPaintInfo textRunPaintInfo(textRun);
41393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    textRunPaintInfo.bounds = boxRect;
41493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (startOffset <= endOffset) {
41593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        textRunPaintInfo.from = startOffset;
41693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        textRunPaintInfo.to = endOffset;
41793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (emphasisMark.isEmpty())
41893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            context->drawText(font, textRunPaintInfo, textOrigin);
41993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        else
42093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset));
42193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    } else {
42293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (endOffset > 0) {
42393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            textRunPaintInfo.from = 0;
42493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            textRunPaintInfo.to = endOffset;
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (emphasisMark.isEmpty())
42693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                context->drawText(font, textRunPaintInfo, textOrigin);
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
42893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset));
4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
43093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (startOffset < truncationPoint) {
43193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            textRunPaintInfo.from = startOffset;
43293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            textRunPaintInfo.to = truncationPoint;
43393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            if (emphasisMark.isEmpty())
43493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                context->drawText(font, textRunPaintInfo, textOrigin);
43593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            else
43693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)                context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset));
43793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        }
43893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
44093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (hasShadow)
44193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        context->clearDrawLooper();
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosition& emphasisPosition) const
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This function returns true if there are text emphasis marks and they are suppressed by ruby text.
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (style->textEmphasisMark() == TextEmphasisMarkNone)
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    emphasisPosition = style->textEmphasisPosition();
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (emphasisPosition == TextEmphasisPositionUnder)
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true; // Ruby text is always over, so it cannot suppress emphasis marks under.
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderBlock* containingBlock = renderer()->containingBlock();
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!containingBlock->isRubyBase())
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true; // This text is not inside a ruby base, so it does not have ruby text over it.
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!containingBlock->parent()->isRubyRun())
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true; // Cannot get the ruby text.
4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderRubyText* rubyText = toRenderRubyRun(containingBlock->parent())->rubyText();
4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // The emphasis marks over are suppressed only if there is a ruby text box and it not empty.
4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return !rubyText || !rubyText->firstLineBox();
4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)enum RotationDirection { Counterclockwise, Clockwise };
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline AffineTransform rotation(const FloatRect& boxRect, RotationDirection clockwise)
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return clockwise ? AffineTransform(0, 1, -1, 0, boxRect.x() + boxRect.maxY(), boxRect.maxY() - boxRect.x())
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        : AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.maxY(), boxRect.x() + boxRect.maxY());
4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /*lineTop*/, LayoutUnit /*lineBottom*/)
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE ||
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline || !m_len)
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit logicalLeftSide = logicalLeftVisualOverflow();
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit logicalRightSide = logicalRightVisualOverflow();
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit logicalStart = logicalLeftSide + (isHorizontal() ? paintOffset.x() : paintOffset.y());
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit logicalExtent = logicalRightSide - logicalLeftSide;
48702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit paintEnd = isHorizontal() ? paintInfo.rect.maxX() : paintInfo.rect.maxY();
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit paintStart = isHorizontal() ? paintInfo.rect.x() : paintInfo.rect.y();
49002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutPoint adjustedPaintOffset = roundedIntPoint(paintOffset);
49202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (logicalStart >= paintEnd || logicalStart + logicalExtent <= paintStart)
4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool isPrinting = textRenderer()->document()->printing();
49702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Determine whether or not we're selected.
4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone;
5005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!haveSelection && paintInfo.phase == PaintPhaseSelection)
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // When only painting the selection, don't bother to paint if there is none.
5025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation != cNoTruncation) {
5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (renderer()->containingBlock()->style()->isLeftToRightDirection() != isLeftToRightDirection()) {
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Make the visible fragment of text hug the edge closest to the rest of the run by moving the origin
5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // at which we start drawing text.
5085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // e.g. In the case of LTR text truncated in an RTL Context, the correct behavior is:
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // |Hello|CBA| -> |...He|CBA|
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // In order to draw the fragment "He" aligned to the right edge of it's box, we need to start drawing
5115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // farther to the right.
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // NOTE: WebKit's behavior differs from that of IE which appears to just overlay the ellipsis on top of the
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // truncated string i.e.  |Hello|CBA| -> |...lo|CBA|
5145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            LayoutUnit widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle());
5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            LayoutUnit widthOfHiddenText = m_logicalWidth - widthOfVisibleText;
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // FIXME: The hit testing logic also needs to take this translation into account.
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            LayoutSize truncationOffset(isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText, 0);
5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            adjustedPaintOffset.move(isHorizontal() ? truncationOffset : truncationOffset.transposedSize());
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    GraphicsContext* context = paintInfo.context;
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    RenderObject* rendererToUse = renderer();
5257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    RenderStyle* styleToUse = rendererToUse->style(isFirstLineStyle());
52602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    adjustedPaintOffset.move(0, styleToUse->isHorizontalWritingMode() ? 0 : -logicalHeight());
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint boxOrigin = locationIncludingFlipping();
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    boxOrigin.move(adjustedPaintOffset.x(), adjustedPaintOffset.y());
5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), logicalHeight()));
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderCombineText* combinedText = styleToUse->hasTextCombine() && textRenderer()->isCombineText() && toRenderCombineText(textRenderer())->isCombined() ? toRenderCombineText(textRenderer()) : 0;
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool shouldRotate = !isHorizontal() && !combinedText;
5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (shouldRotate)
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        context->concatCTM(rotation(boxRect, Clockwise));
5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Determine whether or not we have composition underlines to draw.
540e6d4491e48613634a83c1957c72759da80987961Ben Murdoch    bool containsComposition = renderer()->node() && renderer()->frame()->inputMethodController().compositionNode() == renderer()->node();
541e6d4491e48613634a83c1957c72759da80987961Ben Murdoch    bool useCustomUnderlines = containsComposition && renderer()->frame()->inputMethodController().compositionUsesCustomUnderlines();
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Determine the text colors and selection colors.
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color textFillColor;
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color textStrokeColor;
5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color emphasisMarkColor;
5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float textStrokeWidth = styleToUse->textStrokeWidth();
5487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch
5497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    // Text shadows are disabled when printing. http://crbug.com/258321
5507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    const ShadowData* textShadow = (context->printing() || paintInfo.forceBlackText()) ? 0 : styleToUse->textShadow();
5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
552926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (paintInfo.forceBlackText()) {
5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        textFillColor = Color::black;
5545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        textStrokeColor = Color::black;
5555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        emphasisMarkColor = Color::black;
5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
5577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        textFillColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextFillColor);
55802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool forceBackgroundToWhite = false;
5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (isPrinting) {
5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (styleToUse->printColorAdjust() == PrintColorAdjustEconomy)
5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                forceBackgroundToWhite = true;
5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (textRenderer()->document()->settings() && textRenderer()->document()->settings()->shouldPrintBackgrounds())
5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                forceBackgroundToWhite = false;
5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
5665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Make the text fill color legible against a white background
5685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (forceBackgroundToWhite)
5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            textFillColor = correctedTextColor(textFillColor, Color::white);
5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        textStrokeColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextStrokeColor);
57202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Make the text stroke color legible against a white background
5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (forceBackgroundToWhite)
5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            textStrokeColor = correctedTextColor(textStrokeColor, Color::white);
5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        emphasisMarkColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextEmphasisColor);
57802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Make the text stroke color legible against a white background
5805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (forceBackgroundToWhite)
5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            emphasisMarkColor = correctedTextColor(emphasisMarkColor, Color::white);
5825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection);
5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool paintSelectedTextSeparately = false;
5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color selectionFillColor = textFillColor;
5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color selectionStrokeColor = textStrokeColor;
5895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color selectionEmphasisMarkColor = emphasisMarkColor;
5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float selectionStrokeWidth = textStrokeWidth;
5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const ShadowData* selectionShadow = textShadow;
5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (haveSelection) {
5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Check foreground color first.
594926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor();
59583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch        if (foreground != Color::transparent && foreground != selectionFillColor) {
5965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!paintSelectedTextOnly)
5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                paintSelectedTextSeparately = true;
5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            selectionFillColor = foreground;
5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
601926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        Color emphasisMarkForeground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionEmphasisMarkColor();
60283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch        if (emphasisMarkForeground != Color::transparent && emphasisMarkForeground != selectionEmphasisMarkColor) {
6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!paintSelectedTextOnly)
6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                paintSelectedTextSeparately = true;
6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            selectionEmphasisMarkColor = emphasisMarkForeground;
6065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (RenderStyle* pseudoStyle = renderer()->getCachedPseudoStyle(SELECTION)) {
6097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            // Text shadows are disabled when printing. http://crbug.com/258321
6107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            const ShadowData* shadow = (context->printing() || paintInfo.forceBlackText()) ? 0 : pseudoStyle->textShadow();
6115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (shadow != selectionShadow) {
6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!paintSelectedTextOnly)
6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    paintSelectedTextSeparately = true;
6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                selectionShadow = shadow;
6155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
6165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float strokeWidth = pseudoStyle->textStrokeWidth();
6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (strokeWidth != selectionStrokeWidth) {
6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!paintSelectedTextOnly)
6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    paintSelectedTextSeparately = true;
6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                selectionStrokeWidth = strokeWidth;
6225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
6235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            Color stroke = paintInfo.forceBlackText() ? Color::black : rendererToUse->resolveColor(pseudoStyle, CSSPropertyWebkitTextStrokeColor);
6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (stroke != selectionStrokeColor) {
6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!paintSelectedTextOnly)
6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    paintSelectedTextSeparately = true;
6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                selectionStrokeColor = stroke;
6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Set our font.
6345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const Font& font = styleToUse->font();
6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent());
6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (combinedText)
6395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        combinedText->adjustTextOrigin(textOrigin, boxRect);
6405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // and composition underlines.
6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) {
6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        if (containsComposition && !useCustomUnderlines) {
6465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            paintCompositionBackground(context, boxOrigin, styleToUse, font,
647e6d4491e48613634a83c1957c72759da80987961Ben Murdoch                renderer()->frame()->inputMethodController().compositionStart(),
648e6d4491e48613634a83c1957c72759da80987961Ben Murdoch                renderer()->frame()->inputMethodController().compositionEnd());
649e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        }
6505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintDocumentMarkers(context, boxOrigin, styleToUse, font, true);
6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (haveSelection && !useCustomUnderlines)
6545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            paintSelection(context, boxOrigin, styleToUse, font, selectionFillColor);
6555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (Frame* frame = renderer()->frame()) {
6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (Page* page = frame->page()) {
6595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // FIXME: Right now, InlineTextBoxes never call addRelevantUnpaintedObject() even though they might
6605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // legitimately be unpainted if they are waiting on a slow-loading web font. We should fix that, and
6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // when we do, we will have to account for the fact the InlineTextBoxes do not always have unique
6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // renderers and Page currently relies on each unpainted object having a unique renderer.
6635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (paintInfo.phase == PaintPhaseForeground)
6645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                page->addRelevantRepaintedObject(renderer(), IntRect(boxOrigin.x(), boxOrigin.y(), logicalWidth(), logicalHeight()));
6655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
6665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
6695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int length = m_len;
6705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int maximumLength;
6717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    StringView string;
6725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!combinedText) {
6737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        string = textRenderer()->text().createView();
6747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        if (static_cast<unsigned>(length) != string.length() || m_start)
6757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            string.narrow(m_start, length);
6765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        maximumLength = textRenderer()->textLength() - m_start;
6775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        combinedText->getStringToRender(m_start, string, length);
6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        maximumLength = length;
6805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
682e6d4491e48613634a83c1957c72759da80987961Ben Murdoch    StringBuilder charactersWithHyphen;
6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TextRun textRun = constructTextRun(styleToUse, font, string, maximumLength, hasHyphen() ? &charactersWithHyphen : 0);
6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (hasHyphen())
6855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        length = textRun.length();
6865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int sPos = 0;
6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int ePos = 0;
6895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintSelectedTextOnly || paintSelectedTextSeparately)
6905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        selectionStartEnd(sPos, ePos);
6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation != cNoTruncation) {
6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        sPos = min<int>(sPos, m_truncation);
6945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ePos = min<int>(ePos, m_truncation);
6955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        length = m_truncation;
6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int emphasisMarkOffset = 0;
6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TextEmphasisPosition emphasisMarkPosition;
7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool hasTextEmphasis = getEmphasisMarkPosition(styleToUse, emphasisMarkPosition);
7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const AtomicString& emphasisMark = hasTextEmphasis ? styleToUse->textEmphasisMarkString() : nullAtom;
7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!emphasisMark.isEmpty())
7035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        emphasisMarkOffset = emphasisMarkPosition == TextEmphasisPositionOver ? -font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fontMetrics().descent() + font.emphasisMarkAscent(emphasisMark);
7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!paintSelectedTextOnly) {
7065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // For stroked painting, we have to change the text drawing mode.  It's probably dangerous to leave that mutated as a side
7075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // effect, so only when we know we're stroking, do a save/restore.
7085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        GraphicsContextStateSaver stateSaver(*context, textStrokeWidth > 0);
7095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7105267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth);
7115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!paintSelectedTextSeparately || ePos <= sPos) {
7125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // FIXME: Truncate right-to-left text correctly.
7137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            paintTextWithShadows(context, rendererToUse, font, textRun, nullAtom, 0, 0, length, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
7147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        } else {
7157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            paintTextWithShadows(context, rendererToUse, font, textRun, nullAtom, 0, ePos, sPos, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
7167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        }
7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!emphasisMark.isEmpty()) {
7195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            updateGraphicsContext(context, emphasisMarkColor, textStrokeColor, textStrokeWidth);
7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
7235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (combinedText)
7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                context->concatCTM(rotation(boxRect, Clockwise));
7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!paintSelectedTextSeparately || ePos <= sPos) {
7285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                // FIXME: Truncate right-to-left text correctly.
7297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, 0, length, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
7307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            } else {
7317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch                paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, ePos, sPos, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
7327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            }
7335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (combinedText)
7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                context->concatCTM(rotation(boxRect, Counterclockwise));
7365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) {
7405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // paint only the text that is selected
7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        GraphicsContextStateSaver stateSaver(*context, selectionStrokeWidth > 0);
7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7435267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth);
7447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        paintTextWithShadows(context, rendererToUse, font, textRun, nullAtom, 0, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
7455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!emphasisMark.isEmpty()) {
7465267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            updateGraphicsContext(context, selectionEmphasisMarkColor, textStrokeColor, textStrokeWidth);
7475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
7515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (combinedText)
7525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                context->concatCTM(rotation(boxRect, Clockwise));
7535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, emphasisMarkTextOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (combinedText)
7575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                context->concatCTM(rotation(boxRect, Counterclockwise));
7585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Paint decorations
76293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    TextDecoration textDecorations = styleToUse->textDecorationsInEffect();
76393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSelection) {
7645267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth);
765926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (combinedText)
766926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            context->concatCTM(rotation(boxRect, Clockwise));
7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintDecoration(context, boxOrigin, textDecorations, styleToUse->textDecorationStyle(), textShadow);
768926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (combinedText)
769926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            context->concatCTM(rotation(boxRect, Counterclockwise));
7705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
7715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintInfo.phase == PaintPhaseForeground) {
7735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintDocumentMarkers(context, boxOrigin, styleToUse, font, false);
7745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (useCustomUnderlines) {
776e6d4491e48613634a83c1957c72759da80987961Ben Murdoch            const Vector<CompositionUnderline>& underlines = renderer()->frame()->inputMethodController().customCompositionUnderlines();
7775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            size_t numUnderlines = underlines.size();
7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (size_t index = 0; index < numUnderlines; ++index) {
7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                const CompositionUnderline& underline = underlines[index];
7815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
7825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (underline.endOffset <= start())
7835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    // underline is completely before this run.  This might be an underline that sits
78402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch                    // before the first run we draw, or underlines that were within runs we skipped
7855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    // due to truncation.
7865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    continue;
78702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
7885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (underline.startOffset <= end()) {
7895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    // underline intersects this run.  Paint it.
7905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    paintCompositionUnderline(context, boxOrigin, underline);
7915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    if (underline.endOffset > end() + 1)
7925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        // underline also runs into the next run. Bail now, no more marker advancement.
7935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                        break;
7945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                } else
7955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    // underline is completely after this run, bail.  A later run will paint it.
7965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    break;
7975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
7985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
7995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
80002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
8015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (shouldRotate)
8025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        context->concatCTM(rotation(boxRect, Counterclockwise));
8035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
8065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int startPos, endPos;
8085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (renderer()->selectionState() == RenderObject::SelectionInside) {
8095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        startPos = 0;
8105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        endPos = textRenderer()->textLength();
8115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
8125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        textRenderer()->selectionStartEnd(startPos, endPos);
8135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (renderer()->selectionState() == RenderObject::SelectionStart)
8145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            endPos = textRenderer()->textLength();
8155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else if (renderer()->selectionState() == RenderObject::SelectionEnd)
8165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            startPos = 0;
8175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
8185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    sPos = max(startPos - m_start, 0);
8205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ePos = min(endPos - m_start, (int)m_len);
8215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void alignSelectionRectToDevicePixels(FloatRect& rect)
8245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float maxX = floorf(rect.maxX());
8265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rect.setX(floorf(rect.x()));
8275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    rect.setWidth(roundf(maxX - rect.x()));
8285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, Color textColor)
8315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (context->paintingDisabled())
8335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
8345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // See if we have a selection to paint at all.
8365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int sPos, ePos;
8375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    selectionStartEnd(sPos, ePos);
8385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (sPos >= ePos)
8395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
8405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color c = renderer()->selectionBackgroundColor();
84283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch    if (!c.alpha())
8435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
8445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If the text color ends up being the same as the selection background, invert the selection
8465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // background.
8475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (textColor == c)
8485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
8495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    GraphicsContextStateSaver stateSaver(*context);
8515267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
8525267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
8535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If the text is truncated, let the thing being painted in the truncation
8545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // draw its own highlight.
8555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int length = m_truncation != cNoTruncation ? m_truncation : m_len;
8567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    StringView string = textRenderer()->text().createView();
8575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    if (string.length() != static_cast<unsigned>(length) || m_start)
8597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        string.narrow(m_start, length);
8605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
861e6d4491e48613634a83c1957c72759da80987961Ben Murdoch    StringBuilder charactersWithHyphen;
8625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool respectHyphen = ePos == length && hasHyphen();
8635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TextRun textRun = constructTextRun(style, font, string, textRenderer()->textLength() - m_start, respectHyphen ? &charactersWithHyphen : 0);
8645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (respectHyphen)
8655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ePos = textRun.length();
8665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit selectionBottom = root()->selectionBottom();
8685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    LayoutUnit selectionTop = root()->selectionTopAdjustedForPrecedingBlock();
8695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int deltaY = roundToInt(renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop);
8715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int selHeight = max(0, roundToInt(selectionBottom - selectionTop));
8725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY);
8745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatRect clipRect(localOrigin, FloatSize(m_logicalWidth, selHeight));
8755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    alignSelectionRectToDevicePixels(clipRect);
8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    context->clip(clipRect);
8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8795267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, sPos, ePos);
8805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
8815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, int startPos, int endPos)
8835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
8845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int offset = m_start;
8855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int sPos = max(startPos - offset, 0);
8865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int ePos = min(endPos - offset, (int)m_len);
8875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (sPos >= ePos)
8895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
8905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    GraphicsContextStateSaver stateSaver(*context);
8925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color c = Color(225, 221, 85);
8945267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
8955267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
8965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int selHeight = selectionHeight();
8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY);
9005267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    context->drawHighlightForText(font, constructTextRun(style, font), localOrigin, selHeight, c, sPos, ePos);
9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorationStyle)
9045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
9055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    StrokeStyle strokeStyle = SolidStroke;
9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    switch (decorationStyle) {
9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case TextDecorationStyleSolid:
9085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        strokeStyle = SolidStroke;
9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case TextDecorationStyleDouble:
9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        strokeStyle = DoubleStroke;
9125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
9135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case TextDecorationStyleDotted:
9145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        strokeStyle = DottedStroke;
9155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
9165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case TextDecorationStyleDashed:
9175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        strokeStyle = DashedStroke;
9185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
9195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case TextDecorationStyleWavy:
9205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        strokeStyle = WavyStroke;
9215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
9225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
9235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
9245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return strokeStyle;
9255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
9265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
927926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#if ENABLE(CSS3_TEXT)
928926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, const InlineTextBox* inlineTextBox, const int textDecorationThickness)
929926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
930926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // Compute the gap between the font and the underline. Use at least one
931926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // pixel gap, if underline is thick then use a bigger gap.
932926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    const int gap = max<int>(1, ceilf(textDecorationThickness / 2.0));
933926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
934926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // According to the specification TextUnderlinePositionAuto should default to 'alphabetic' for horizontal text
935926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // and to 'under Left' for vertical text (e.g. japanese). We support only horizontal text for now.
936926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    switch (underlinePosition) {
937926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    case TextUnderlinePositionAlphabetic:
938926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    case TextUnderlinePositionAuto:
939926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return fontMetrics.ascent() + gap; // Position underline near the alphabetic baseline.
940926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    case TextUnderlinePositionUnder: {
941926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // Position underline relative to the under edge of the lowest element's content box.
942926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        const float offset = inlineTextBox->root()->maxLogicalTop() - inlineTextBox->logicalTop();
943926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (offset > 0)
944926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            return inlineTextBox->logicalHeight() + gap + offset;
945926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return inlineTextBox->logicalHeight() + gap;
946926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
947926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
948926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
949926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    ASSERT_NOT_REACHED();
950926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return fontMetrics.ascent() + gap;
951926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
952926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#endif // CSS3_TEXT
953926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
95453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)static void adjustStepToDecorationLength(float& step, float& controlPointDistance, float length)
95553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles){
95653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    ASSERT(step > 0);
95753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
95853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if (length <= 0)
95953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        return;
96053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
96153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    unsigned stepCount = static_cast<unsigned>(length / step);
96253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
96353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // Each Bezier curve starts at the same pixel that the previous one
96453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // ended. We need to subtract (stepCount - 1) pixels when calculating the
96553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // length covered to account for that.
96653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    float uncoveredLength = length - (stepCount * step - (stepCount - 1));
96753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    float adjustment = uncoveredLength / stepCount;
96853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    step += adjustment;
96953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    controlPointDistance += adjustment;
97053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
97153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
97253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)/*
97353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * Draw one cubic Bezier curve and repeat the same pattern long the the decoration's axis.
97453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * The start point (p1), controlPoint1, controlPoint2 and end point (p2) of the Bezier curve
97553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * form a diamond shape:
97653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *
97753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                              step
97853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                         |-----------|
97953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *
98053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                   controlPoint1
98153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                         +
98253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *
98353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *
98453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                  . .
98553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                .     .
98653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *              .         .
98753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * (x1, y1) p1 +           .            + p2 (x2, y2) - <--- Decoration's axis
98853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                          .         .               |
98953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                            .     .                 |
99053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                              . .                   | controlPointDistance
99153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                                                    |
99253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                                                    |
99353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                         +                          -
99453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                   controlPoint2
99553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *
99653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *             |-----------|
99753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *                 step
99853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) */
99953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)static void strokeWavyTextDecoration(GraphicsContext* context, FloatPoint& p1, FloatPoint& p2, float strokeThickness)
100053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles){
100153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    context->adjustLineToPixelBoundaries(p1, p2, strokeThickness, context->strokeStyle());
100253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
100353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    Path path;
100453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    path.moveTo(p1);
100553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
100653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // Distance between decoration's axis and Bezier curve's control points.
100753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // The height of the curve is based on this distance. Use a minimum of 6 pixels distance since
100853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // the actual curve passes approximately at half of that distance, that is 3 pixels.
100953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // The minimum height of the curve is also approximately 3 pixels. Increases the curve's height
101053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // as strockThickness increases to make the curve looks better.
101153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    float controlPointDistance = 3 * max<float>(2, strokeThickness);
101253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
101353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // Increment used to form the diamond shape between start point (p1), control
101453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // points and end point (p2) along the axis of the decoration. Makes the
101553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // curve wider as strockThickness increases to make the curve looks better.
101653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    float step = 2 * max<float>(2, strokeThickness);
101753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
101853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    bool isVerticalLine = (p1.x() == p2.x());
101953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
102053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if (isVerticalLine) {
102153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        ASSERT(p1.x() == p2.x());
102253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
102353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        float xAxis = p1.x();
102453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        float y1;
102553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        float y2;
102653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
102753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if (p1.y() < p2.y()) {
102853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            y1 = p1.y();
102953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            y2 = p2.y();
103053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        } else {
103153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            y1 = p2.y();
103253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            y2 = p1.y();
103353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        }
103453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
103553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        adjustStepToDecorationLength(step, controlPointDistance, y2 - y1);
103653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        FloatPoint controlPoint1(xAxis + controlPointDistance, 0);
103753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        FloatPoint controlPoint2(xAxis - controlPointDistance, 0);
103853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
103953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        for (float y = y1; y + 2 * step <= y2;) {
104053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            controlPoint1.setY(y + step);
104153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            controlPoint2.setY(y + step);
104253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            y += 2 * step;
104353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(xAxis, y));
104453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        }
104553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    } else {
104653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        ASSERT(p1.y() == p2.y());
104753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
104853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        float yAxis = p1.y();
104953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        float x1;
105053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        float x2;
105153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
105253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if (p1.x() < p2.x()) {
105353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            x1 = p1.x();
105453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            x2 = p2.x();
105553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        } else {
105653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            x1 = p2.x();
105753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            x2 = p1.x();
105853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        }
105953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
106053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        adjustStepToDecorationLength(step, controlPointDistance, x2 - x1);
106153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        FloatPoint controlPoint1(0, yAxis + controlPointDistance);
106253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        FloatPoint controlPoint2(0, yAxis - controlPointDistance);
106353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
106453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        for (float x = x1; x + 2 * step <= x2;) {
106553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            controlPoint1.setX(x + step);
106653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            controlPoint2.setX(x + step);
106753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            x += 2 * step;
106853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis));
106953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        }
107053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    }
107153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
107253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    context->setShouldAntialias(true);
107353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    context->strokePath(path);
107453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
107553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
107693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, TextDecorationStyle decorationStyle, const ShadowData* shadow)
10775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
107893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    GraphicsContextStateSaver stateSaver(*context);
107993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
10805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: We should improve this rule and not always just assume 1.
10815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const float textDecorationThickness = 1.f;
10825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation == cFullTruncation)
10845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
10855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint localOrigin = boxOrigin;
10875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
10885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float width = m_logicalWidth;
10895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation != cNoTruncation) {
10905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle());
10915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!isLeftToRightDirection())
10925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            localOrigin.move(m_logicalWidth - width, 0);
10935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
109402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
10955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Get the text decoration colors.
10965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Color underline, overline, linethrough;
10975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    renderer()->getTextDecorationColors(deco, underline, overline, linethrough, true);
10985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isFirstLineStyle())
10995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        renderer()->getTextDecorationColors(deco, underline, overline, linethrough, true, true);
110002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
11015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Use a special function for underlines to get the positioning exactly right.
11025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool isPrinting = textRenderer()->document()->printing();
11035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    context->setStrokeThickness(textDecorationThickness);
11045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
110593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.alpha() == 255);
11065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderStyle* styleToUse = renderer()->style(isFirstLineStyle());
11085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int baseline = styleToUse->fontMetrics().ascent();
11095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int extraOffset = 0;
11115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!linesAreOpaque && shadow && shadow->next()) {
11125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2));
11135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (const ShadowData* s = shadow; s; s = s->next()) {
11145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            FloatRect shadowRect(localOrigin, FloatSize(width, baseline + 2));
11155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            shadowRect.inflate(s->blur());
11165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            int shadowX = isHorizontal() ? s->x() : s->y();
11175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            int shadowY = isHorizontal() ? s->y() : -s->x();
11185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            shadowRect.move(shadowX, shadowY);
11195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            clipRect.unite(shadowRect);
11205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            extraOffset = max(extraOffset, max(0, shadowY) + s->blur());
11215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        context->clip(clipRect);
11235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        extraOffset += baseline + 2;
11245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        localOrigin.move(0, extraOffset);
11255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
11265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    do {
11285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (shadow) {
11295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (!shadow->next()) {
11305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                // The last set of lines paints normally inside the clip.
11315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                localOrigin.move(0, -extraOffset);
11325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                extraOffset = 0;
11335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
11345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            int shadowX = isHorizontal() ? shadow->x() : shadow->y();
11355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            int shadowY = isHorizontal() ? shadow->y() : -shadow->x();
113683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch            context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow->blur(),
113783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch                renderer()->resolveColor(shadow->color(), Color::stdShadowColor));
11385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            shadow = shadow->next();
11395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Offset between lines - always non-zero, so lines never cross each other.
11425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        float doubleOffset = textDecorationThickness + 1.f;
11435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        context->setStrokeStyle(textDecorationStyleToStrokeStyle(decorationStyle));
114493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (deco & TextDecorationUnderline) {
11455267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            context->setStrokeColor(underline);
11465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if ENABLE(CSS3_TEXT)
1147926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            TextUnderlinePosition underlinePosition = styleToUse->textUnderlinePosition();
1148926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            const int underlineOffset = computeUnderlineOffset(underlinePosition, styleToUse->fontMetrics(), this, textDecorationThickness);
11495267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#else
11505267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            const int underlineOffset = styleToUse->fontMetrics().ascent() + max<int>(1, ceilf(textDecorationThickness / 2.0));
11515267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#endif // CSS3_TEXT
1152926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
115353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            switch (decorationStyle) {
115453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            case TextDecorationStyleWavy: {
115553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                FloatPoint start(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset);
115653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                FloatPoint end(localOrigin.x() + width, localOrigin.y() + underlineOffset + doubleOffset);
115753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                strokeWavyTextDecoration(context, start, end, textDecorationThickness);
115853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                break;
115953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            }
116053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            default:
116153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset), width, isPrinting);
116253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
116353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                if (decorationStyle == TextDecorationStyleDouble)
116453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset), width, isPrinting);
116553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            }
11665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
116793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (deco & TextDecorationOverline) {
11685267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            context->setStrokeColor(overline);
116953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            switch (decorationStyle) {
117053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            case TextDecorationStyleWavy: {
117153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                FloatPoint start(localOrigin.x(), localOrigin.y() - doubleOffset);
117253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                FloatPoint end(localOrigin.x() + width, localOrigin.y() - doubleOffset);
117353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                strokeWavyTextDecoration(context, start, end, textDecorationThickness);
117453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                break;
117553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            }
117653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            default:
117753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                context->drawLineForText(localOrigin, width, isPrinting);
117853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                if (decorationStyle == TextDecorationStyleDouble)
117953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() - doubleOffset), width, isPrinting);
118053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            }
11815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
118293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (deco & TextDecorationLineThrough) {
11835267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)            context->setStrokeColor(linethrough);
118453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            switch (decorationStyle) {
118553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            case TextDecorationStyleWavy: {
118653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                FloatPoint start(localOrigin.x(), localOrigin.y() + 2 * baseline / 3);
118753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                FloatPoint end(localOrigin.x() + width, localOrigin.y() + 2 * baseline / 3);
118853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                strokeWavyTextDecoration(context, start, end, textDecorationThickness);
118953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                break;
119053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            }
119153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            default:
119253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting);
119353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                if (decorationStyle == TextDecorationStyleDouble)
119453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)                    context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + doubleOffset + 2 * baseline / 3), width, isPrinting);
119553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            }
11965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
11975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } while (shadow);
11985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
11995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentMarker::MarkerType markerType)
12015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
12025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    switch (markerType) {
12035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case DocumentMarker::Spelling:
12045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return GraphicsContext::DocumentMarkerSpellingLineStyle;
12055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case DocumentMarker::Grammar:
12065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return GraphicsContext::DocumentMarkerGrammarLineStyle;
12075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    default:
12085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
12095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return GraphicsContext::DocumentMarkerSpellingLineStyle;
12105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
12115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
12125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::paintDocumentMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, DocumentMarker* marker, RenderStyle* style, const Font& font, bool grammar)
12145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
12155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Never print spelling/grammar markers (5327887)
12165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (textRenderer()->document()->printing())
12175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
12185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation == cFullTruncation)
12205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
12215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float start = 0; // start of line to draw, relative to tx
12235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float width = m_logicalWidth; // how much line to draw
12245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Determine whether we need to measure text
12265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool markerSpansWholeBox = true;
12275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_start <= (int)marker->startOffset())
12285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markerSpansWholeBox = false;
12295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if ((end() + 1) != marker->endOffset()) // end points at the last char, not past it
12305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markerSpansWholeBox = false;
12315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation != cNoTruncation)
12325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        markerSpansWholeBox = false;
12335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1234e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    if (!markerSpansWholeBox || grammar) {
12355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int startPosition = max<int>(marker->startOffset() - m_start, 0);
12365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int endPosition = min<int>(marker->endOffset() - m_start, m_len);
123702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
12385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (m_truncation != cNoTruncation)
12395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            endPosition = min<int>(endPosition, m_truncation);
12405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Calculate start & width
12425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
12435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int selHeight = selectionHeight();
12445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        FloatPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY);
12455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        TextRun run = constructTextRun(style, font);
12465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // FIXME: Convert the document markers to float rects.
12485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, selHeight, startPosition, endPosition));
12495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        start = markerRect.x() - startPoint.x();
12505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        width = markerRect.width();
125102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
12525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Store rendered rects for bad grammar markers, so we can hit-test against it elsewhere in order to
12535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // display a toolTip. We don't do this for misspelling markers.
1254e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)        if (grammar) {
12555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            markerRect.move(-boxOrigin.x(), -boxOrigin.y());
1256926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
12575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            toRenderedDocumentMarker(marker)->setRenderedRect(markerRect);
12585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
12595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
126002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
12615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // IMPORTANT: The misspelling underline is not considered when calculating the text bounds, so we have to
12625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // make sure to fit within those bounds.  This means the top pixel(s) of the underline will overlap the
12635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // bottom pixel(s) of the glyphs in smaller font sizes.  The alternatives are to increase the line spacing (bad!!)
12645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // or decrease the underline thickness.  The overlap is actually the most useful, and matches what AppKit does.
12655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // So, we generally place the underline at the bottom of the text, but in larger fonts that's not so good so
12665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // we pin to two pixels under the baseline.
1267e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles)    int lineThickness = misspellingLineThickness;
12685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int baseline = renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
12695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int descent = logicalHeight() - baseline;
12705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int underlineOffset;
12715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (descent <= (2 + lineThickness)) {
12725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Place the underline at the very bottom of the text in small/medium fonts.
12735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        underlineOffset = logicalHeight() - lineThickness;
12745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else {
12755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // In larger fonts, though, place the underline up near the baseline to prevent a big gap.
12765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        underlineOffset = baseline + 2;
12775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
12785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    pt->drawLineForDocumentMarker(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + underlineOffset), width, lineStyleForMarkerType(marker->type()));
12795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
12805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, DocumentMarker* marker, RenderStyle* style, const Font& font)
12825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
12835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Use same y positioning and height as for selection, so that when the selection and this highlight are on
12845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // the same word there are no pieces sticking out.
12855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
12865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int selHeight = selectionHeight();
12875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int sPos = max(marker->startOffset() - m_start, (unsigned)0);
12895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int ePos = min(marker->endOffset() - m_start, (unsigned)m_len);
12905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TextRun run = constructTextRun(style, font);
12915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates.
12935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(x(), selectionTop()), selHeight, sPos, ePos));
1294926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
12955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    toRenderedDocumentMarker(marker)->setRenderedRect(markerRect);
12965267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
12975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Optionally highlight the text
12985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (renderer()->frame()->editor()->markedTextMatchesAreHighlighted()) {
12995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Color color = marker->activeMatch() ?
13005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            renderer()->theme()->platformActiveTextSearchHighlightColor() :
13015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            renderer()->theme()->platformInactiveTextSearchHighlightColor();
13025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        GraphicsContextStateSaver stateSaver(*pt);
13035267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        updateGraphicsContext(pt, color, color, 0); // Don't draw text at all!
13045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pt->clip(FloatRect(boxOrigin.x(), boxOrigin.y() - deltaY, m_logicalWidth, selHeight));
13055267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        pt->drawHighlightForText(font, run, FloatPoint(boxOrigin.x(), boxOrigin.y() - deltaY), selHeight, color, sPos, ePos);
13065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, bool background)
13105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!renderer()->node())
13125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
13135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<DocumentMarker*> markers = renderer()->document()->markers()->markersFor(renderer()->node());
13155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Vector<DocumentMarker*>::const_iterator markerIt = markers.begin();
13165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Give any document markers that touch this run a chance to draw before the text has been drawn.
13185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Note end() points at the last char, not one past it like endOffset and ranges do.
13195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for ( ; markerIt != markers.end(); markerIt++) {
13205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        DocumentMarker* marker = *markerIt;
132102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Paint either the background markers or the foreground markers, but not both
13235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        switch (marker->type()) {
13245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            case DocumentMarker::Grammar:
13255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            case DocumentMarker::Spelling:
13265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (background)
13275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    continue;
13285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
13295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            case DocumentMarker::TextMatch:
13305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                if (!background)
13315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    continue;
13325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
13335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            default:
13345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                continue;
13355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
13365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (marker->endOffset() <= start())
13385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // marker is completely before this run.  This might be a marker that sits before the
13395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // first run we draw, or markers that were within runs we skipped due to truncation.
13405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
134102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (marker->startOffset() > end())
13435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // marker is completely after this run, bail.  A later run will paint it.
13445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
134502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // marker intersects this run.  Paint it.
13475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        switch (marker->type()) {
13485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            case DocumentMarker::Spelling:
13495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                paintDocumentMarker(pt, boxOrigin, marker, style, font, false);
13505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
13515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            case DocumentMarker::Grammar:
13525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                paintDocumentMarker(pt, boxOrigin, marker, style, font, true);
13535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
13545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            case DocumentMarker::TextMatch:
13555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                paintTextMatchMarker(pt, boxOrigin, marker, style, font);
13565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
13575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            default:
13585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ASSERT_NOT_REACHED();
13595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
13605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
13635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const FloatPoint& boxOrigin, const CompositionUnderline& underline)
13655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation == cFullTruncation)
13675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
136802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
13695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float start = 0; // start of line to draw, relative to tx
13705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float width = m_logicalWidth; // how much line to draw
13715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool useWholeWidth = true;
13725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned paintStart = m_start;
13735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned paintEnd = end() + 1; // end points at the last char, not past it
13745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintStart <= underline.startOffset) {
13755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintStart = underline.startOffset;
13765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        useWholeWidth = false;
13775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        start = toRenderText(renderer())->width(m_start, paintStart - m_start, textPos(), isFirstLineStyle());
13785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintEnd != underline.endOffset) {      // end points at the last char, not past it
13805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintEnd = min(paintEnd, (unsigned)underline.endOffset);
13815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        useWholeWidth = false;
13825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_truncation != cNoTruncation) {
13845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintEnd = min(paintEnd, (unsigned)m_start + m_truncation);
13855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        useWholeWidth = false;
13865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!useWholeWidth) {
13885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        width = toRenderText(renderer())->width(paintStart, paintEnd - paintStart, textPos() + start, isFirstLineStyle());
13895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
13905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline.
13925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // All other marked text underlines are 1px thick.
13935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If there's not enough space the underline will touch or overlap characters.
13945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int lineThickness = 1;
13955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int baseline = renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
13965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (underline.thick && logicalHeight() - baseline >= 2)
13975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        lineThickness = 2;
13985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
13995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We need to have some space between underlines of subsequent clauses, because some input methods do not use different underline styles for those.
14005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We make each line shorter, which has a harmless side effect of shortening the first and last clauses, too.
14015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    start += 1;
14025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    width -= 2;
14035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14045267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    ctx->setStrokeColor(underline.color);
14055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ctx->setStrokeThickness(lineThickness);
14065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ctx->drawLineForText(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + logicalHeight() - lineThickness), width, textRenderer()->document()->printing());
14075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int InlineTextBox::caretMinOffset() const
14105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_start;
14125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int InlineTextBox::caretMaxOffset() const
14155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_start + m_len;
14175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float InlineTextBox::textPos() const
14205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // When computing the width of a text run, RenderBlock::computeInlineDirectionPositionsForLine() doesn't include the actual offset
14225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // from the containing block edge in its measurement. textPos() should be consistent so the text are rendered in the same width.
14235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (logicalLeft() == 0)
14245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
14255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return logicalLeft() - root()->logicalLeft();
14265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs) const
14295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isLineBreak())
14315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return 0;
14325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (lineOffset - logicalLeft() > logicalWidth())
14345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return isLeftToRightDirection() ? len() : 0;
14355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (lineOffset - logicalLeft() < 0)
14365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return isLeftToRightDirection() ? 0 : len();
14375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FontCachePurgePreventer fontCachePurgePreventer;
14395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderText* text = toRenderText(renderer());
14415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderStyle* style = text->style(isFirstLineStyle());
14425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const Font& font = style->font();
14435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return font.offsetForPosition(constructTextRun(style, font), lineOffset - logicalLeft(), includePartialGlyphs);
14445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float InlineTextBox::positionForOffset(int offset) const
14475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(offset >= m_start);
14495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(offset <= m_start + m_len);
14505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isLineBreak())
14525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return logicalLeft();
14535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FontCachePurgePreventer fontCachePurgePreventer;
14555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderText* text = toRenderText(renderer());
14575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderStyle* styleToUse = text->style(isFirstLineStyle());
14585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(styleToUse);
14595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const Font& font = styleToUse->font();
14605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int from = !isLeftToRightDirection() ? offset - m_start : 0;
14615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int to = !isLeftToRightDirection() ? m_len : offset - m_start;
14625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: Do we need to add rightBearing here?
14635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return font.selectionRectForText(constructTextRun(styleToUse, font), IntPoint(logicalLeft(), 0), 0, from, to).maxX();
14645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool InlineTextBox::containsCaretOffset(int offset) const
14675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Offsets before the box are never "in".
14695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (offset < m_start)
14705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
14715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int pastEnd = m_start + m_len;
14735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Offsets inside the box (not at either edge) are always "in".
14755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (offset < pastEnd)
14765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
14775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Offsets outside the box are always "out".
14795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (offset > pastEnd)
14805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
14815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Offsets at the end are "out" for line breaks (they are on the next line).
14835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isLineBreak())
14845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
14855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Offsets at the end are "in" for normal boxes (but the caller has to check affinity).
14875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
14885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
14895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1490e6d4491e48613634a83c1957c72759da80987961Ben MurdochTextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, StringBuilder* charactersWithHyphen) const
14915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
14925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(style);
14935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderText* textRenderer = this->textRenderer();
14955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(textRenderer);
14965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(textRenderer->text());
14975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch    StringView string = textRenderer->text().createView();
14995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned startPos = start();
15005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned length = len();
15015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (string.length() != length || startPos)
15037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        string.narrow(startPos, length);
15045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return constructTextRun(style, font, string, textRenderer->textLength() - startPos, charactersWithHyphen);
15065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1508e6d4491e48613634a83c1957c72759da80987961Ben MurdochTextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, StringView string, int maximumLength, StringBuilder* charactersWithHyphen) const
15095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(style);
15115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderText* textRenderer = this->textRenderer();
15135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(textRenderer);
15145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (charactersWithHyphen) {
1516e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        const AtomicString& hyphenString = style->hyphenString();
1517e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        charactersWithHyphen->reserveCapacity(string.length() + hyphenString.length());
1518e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        charactersWithHyphen->append(string);
1519e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        charactersWithHyphen->append(hyphenString);
1520e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        string = charactersWithHyphen->toString().createView();
1521e6d4491e48613634a83c1957c72759da80987961Ben Murdoch        maximumLength = string.length();
15225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
15235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1524e6d4491e48613634a83c1957c72759da80987961Ben Murdoch    ASSERT(maximumLength >= static_cast<int>(string.length()));
15255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    TextRun run(string, textPos(), expansion(), expansionBehavior(), direction(), dirOverride() || style->rtlOrdering() == VisualOrder, !textRenderer->canUseSimpleFontCodePath());
15275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    run.setTabSize(!style->collapseWhiteSpace(), style->tabSize());
15285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (textRunNeedsRenderingContext(font))
15295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        run.setRenderingContext(SVGTextRunRenderingContext::create(textRenderer));
15305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring.
15325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    run.setCharactersLength(maximumLength);
15335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(run.charactersLength() >= run.length());
15345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return run;
15355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifndef NDEBUG
15385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const char* InlineTextBox::boxName() const
15405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return "InlineTextBox";
15425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void InlineTextBox::showBox(int printedCharacters) const
15455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
15465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const RenderText* obj = toRenderText(renderer());
15475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String value = obj->text();
15485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value = value.substring(start(), len());
15495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value.replaceWithLiteral('\\', "\\\\");
15505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    value.replaceWithLiteral('\n', "\\n");
15515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
15525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
15535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fputc(' ', stderr);
15545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    printedCharacters = fprintf(stderr, "\t%s %p", obj->renderName(), obj);
15555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const int rendererCharacterOffset = 24;
15565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (; printedCharacters < rendererCharacterOffset; printedCharacters++)
15575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        fputc(' ', stderr);
15585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    fprintf(stderr, "(%d,%d) \"%s\"\n", start(), start() + len(), value.utf8().data());
15595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
15605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
15625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore
1564