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