📄 inlinetextbox.cpp
字号:
/* * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "config.h"#include "InlineTextBox.h"#include "ChromeClient.h"#include "Document.h"#include "Editor.h"#include "Frame.h"#include "GraphicsContext.h"#include "HitTestResult.h"#include "Page.h"#include "RenderArena.h"#include "RenderBlock.h"#include "RenderTheme.h"#include "Text.h"#include "break_lines.h"#include <wtf/AlwaysInline.h>using namespace std;namespace WebCore {int InlineTextBox::height() const{ return m_treatAsText ? renderer()->style(m_firstLine)->font().height() : 0;}int InlineTextBox::selectionTop(){ return root()->selectionTop();}int InlineTextBox::selectionHeight(){ return root()->selectionHeight();}bool InlineTextBox::isSelected(int startPos, int endPos) const{ int sPos = max(startPos - m_start, 0); int ePos = min(endPos - m_start, (int)m_len); return (sPos < ePos);}RenderObject::SelectionState InlineTextBox::selectionState(){ RenderObject::SelectionState state = renderer()->selectionState(); if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || state == RenderObject::SelectionBoth) { int startPos, endPos; renderer()->selectionStartEnd(startPos, endPos); // The position after a hard line break is considered to be past its end. int lastSelectable = start() + len() - (isLineBreak() ? 1 : 0); bool start = (state != RenderObject::SelectionEnd && startPos >= m_start && startPos < m_start + m_len); bool end = (state != RenderObject::SelectionStart && endPos > m_start && endPos <= lastSelectable); if (start && end) state = RenderObject::SelectionBoth; else if (start) state = RenderObject::SelectionStart; else if (end) state = RenderObject::SelectionEnd; else if ((state == RenderObject::SelectionEnd || startPos < m_start) && (state == RenderObject::SelectionStart || endPos > lastSelectable)) state = RenderObject::SelectionInside; else if (state == RenderObject::SelectionBoth) state = RenderObject::SelectionNone; } return state;}IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos){ int sPos = max(startPos - m_start, 0); int ePos = min(endPos - m_start, (int)m_len); if (sPos >= ePos) return IntRect(); RenderText* textObj = textRenderer(); int selTop = selectionTop(); int selHeight = selectionHeight(); const Font& f = textObj->style(m_firstLine)->font(); IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(textObj->text()->characters() + m_start, m_len, textObj->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride), IntPoint(tx + m_x, ty + selTop), selHeight, sPos, ePos)); if (r.x() > tx + m_x + m_width) r.setWidth(0); else if (r.right() - 1 > tx + m_x + m_width) r.setWidth(tx + m_x + m_width - r.x()); return r;}void InlineTextBox::deleteLine(RenderArena* arena){ toRenderText(renderer())->removeTextBox(this); destroy(arena);}void InlineTextBox::extractLine(){ if (m_extracted) return; toRenderText(renderer())->extractTextBox(this);}void InlineTextBox::attachLine(){ if (!m_extracted) return; toRenderText(renderer())->attachTextBox(this);}int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox){ if (foundBox) { m_truncation = cFullTruncation; return -1; } int ellipsisX = ltr ? blockEdge - ellipsisWidth : blockEdge + ellipsisWidth; // Criteria for full truncation: // LTR: the left edge of the ellipsis is to the left of our text run. // RTL: the right edge of the ellipsis is to the right of our text run. bool ltrFullTruncation = ltr && ellipsisX <= m_x; bool rtlFullTruncation = !ltr && ellipsisX >= (m_x + m_width); if (ltrFullTruncation || rtlFullTruncation) { // Too far. Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box. m_truncation = cFullTruncation; foundBox = true; return -1; } bool ltrEllipsisWithinBox = ltr && (ellipsisX < m_x + m_width); bool rtlEllipsisWithinBox = !ltr && (ellipsisX > m_x); if (ltrEllipsisWithinBox || rtlEllipsisWithinBox) { if (ltr && direction() == RTL || !ltr && direction() == LTR) return -1; // FIXME: Support cases in which the last run's directionality differs from the context. foundBox = true; int offset = offsetForPosition(ellipsisX, false); if (offset == 0) { // No characters should be rendered. Set ourselves to full truncation and place the ellipsis at the min of our start // and the ellipsis edge. m_truncation = cFullTruncation; return min(ellipsisX, m_x); } // Set the truncation index on the text run. The ellipsis needs to be placed just after the last visible character. m_truncation = offset; if (ltr) return m_x + toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine); else return m_x + (m_width - toRenderText(renderer())->width(m_start, offset, textPos(), m_firstLine)) - ellipsisWidth; } return -1;}Color correctedTextColor(Color textColor, Color backgroundColor) { // Adjust the text color if it is too close to the background color, // by darkening or lightening it to move it further away. int d = differenceSquared(textColor, backgroundColor); // semi-arbitrarily chose 65025 (255^2) value here after a few tests; if (d > 65025) { return textColor; } int distanceFromWhite = differenceSquared(textColor, Color::white); int distanceFromBlack = differenceSquared(textColor, Color::black); if (distanceFromWhite < distanceFromBlack) { return textColor.dark(); } return textColor.light();}void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness){ int mode = context->textDrawingMode(); if (strokeThickness > 0) { int newMode = mode | cTextStroke; if (mode != newMode) { context->setTextDrawingMode(newMode); mode = newMode; } } if (mode & cTextFill && fillColor != context->fillColor()) context->setFillColor(fillColor); if (mode & cTextStroke) { if (strokeColor != context->strokeColor()) context->setStrokeColor(strokeColor); if (strokeThickness != context->strokeThickness()) context->setStrokeThickness(strokeThickness); }}bool InlineTextBox::isLineBreak() const{ return renderer()->isBR() || (renderer()->style()->preserveNewline() && len() == 1 && (*textRenderer()->text())[start()] == '\n');}bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, int x, int y, int tx, int ty){ if (isLineBreak()) return false; IntRect rect(tx + m_x, ty + m_y, m_width, height()); if (m_truncation != cFullTruncation && visibleToHitTesting() && rect.contains(x, y)) { renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } return false;}static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, int startOffset, int endOffset, const IntPoint& textOrigin, int x, int y, int w, int h, ShadowData* shadow, bool stroked){ do { IntSize extraOffset; if (shadow) { IntSize shadowOffset(shadow->x, shadow->y); int shadowBlur = shadow->blur; const Color& shadowColor = shadow->color; if (shadow->next || stroked) { IntRect shadowRect(x, y, w, h); shadowRect.inflate(shadowBlur); shadowRect.move(shadowOffset); context->save(); context->clip(shadowRect); extraOffset = IntSize(0, 2 * h + max(0, shadowOffset.height()) + shadowBlur); shadowOffset -= extraOffset; } context->setShadow(shadowOffset, shadowBlur, shadowColor); } if (startOffset <= endOffset) context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset); else { if (endOffset > 0) context->drawText(font, textRun, textOrigin + extraOffset, 0, endOffset); if (startOffset < textRun.length()) context->drawText(font, textRun, textOrigin + extraOffset, startOffset); } if (!shadow) break; if (shadow->next || stroked) context->restore(); else context->clearShadow(); shadow = shadow->next; } while (shadow || stroked);}void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty){ if (isLineBreak() || !renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline) return; ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines); int xPos = tx + m_x - parent()->maxHorizontalVisualOverflow(); int w = width() + 2 * parent()->maxHorizontalVisualOverflow(); if (xPos >= paintInfo.rect.right() || xPos + w <= paintInfo.rect.x()) return; bool isPrinting = textRenderer()->document()->printing(); // Determine whether or not we're selected. bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone; if (!haveSelection && paintInfo.phase == PaintPhaseSelection) // When only painting the selection, don't bother to paint if there is none. return; GraphicsContext* context = paintInfo.context; // Determine whether or not we have composition underlines to draw. bool containsComposition = renderer()->node() && renderer()->document()->frame()->editor()->compositionNode() == renderer()->node();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -