📄 render_text.cpp
字号:
/** * This file is part of the DOM implementation for KDE. * * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004 Apple Computer, Inc. * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * *///#define DEBUG_LAYOUT//#define BIDI_DEBUG#include "rendering/render_canvas.h"#include "rendering/render_text.h"#include "rendering/break_lines.h"#include "xml/dom_nodeimpl.h"#include "xml/dom_docimpl.h"#include "xml/dom_position.h"#include "render_arena.h"#include "misc/loader.h"#include <qpainter.h>#include <kdebug.h>#include <assert.h>using namespace khtml;using namespace DOM;#ifndef NDEBUGstatic bool inInlineTextBoxDetach;#endifvoid InlineTextBox::detach(RenderArena* renderArena){#ifndef NDEBUG inInlineTextBoxDetach = true;#endif delete this;#ifndef NDEBUG inInlineTextBoxDetach = false;#endif // Recover the size left there for us by operator delete and free the memory. renderArena->free(*(size_t *)this, this);}void* InlineTextBox::operator new(size_t sz, RenderArena* renderArena) throw(){ return renderArena->allocate(sz);}void InlineTextBox::operator delete(void* ptr, size_t sz){ assert(inInlineTextBoxDetach); // Stash size where detach can find it. *(size_t *)ptr = sz;}void InlineTextBox::deleteLine(RenderArena* arena){ static_cast<RenderText*>(m_object)->removeTextBox(this); detach(arena);}void InlineTextBox::extractLine(){ if (m_extracted) return; static_cast<RenderText*>(m_object)->extractTextBox(this);}void InlineTextBox::attachLine(){ if (!m_extracted) return; static_cast<RenderText*>(m_object)->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; // For LTR, if the left edge of the ellipsis is to the left of our text run, then we are the run that will get truncated. if (ltr) { if (ellipsisX <= m_x) { // 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; } if (ellipsisX < m_x + m_width) { if (m_reversed) return -1; // FIXME: Support LTR truncation when the last run is RTL someday. 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 kMin(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 + m_start; return m_x + static_cast<RenderText*>(m_object)->width(m_start, offset, m_firstLine); } } else { // FIXME: Support RTL truncation someday, including both modes (when the leftmost run on the line is either RTL or LTR) } return -1;}void InlineTextBox::paintSelection(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos, bool extendSelection){ int offset = m_start; int sPos = kMax(startPos - offset, 0); int ePos = kMin(endPos - offset, (int)m_len); if (sPos >= ePos) return; p->save();#if APPLE_CHANGES // Macintosh-style text highlighting is to draw with a particular background color, not invert. QColor textColor = style->color(); QColor c = p->selectedTextBackgroundColor(); // if text color and selection background color are identical, invert background color. if (textColor == c) c = QColor(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); RenderStyle* pseudoStyle = object()->getPseudoStyle(RenderStyle::SELECTION); if (pseudoStyle && pseudoStyle->backgroundColor().isValid()) c = pseudoStyle->backgroundColor(); p->setPen(c); // Don't draw text at all! #else QColor c = style->color(); p->setPen(QColor(0xff-c.red(),0xff-c.green(),0xff-c.blue())); ty + m_baseline;#endif #if APPLE_CHANGES // Do the calculations to draw selections as tall as the line. // Use the bottom of the line above as the y position (if there is one, // otherwise use the top of this renderer's line) and the height of the line as the height. // This mimics Cocoa. RenderBlock *cb = object()->containingBlock(); if (root()->prevRootBox()) ty = root()->prevRootBox()->bottomOverflow(); else ty = root()->topOverflow(); int h = root()->bottomOverflow() - ty; int absx, absy; cb->absolutePosition(absx, absy); int x = m_x + tx; int minX = x; int maxX = x; if ((extendSelection || startPos < m_start) && root()->firstLeafChild() == this) minX = absx + kMax(cb->leftOffset(ty), cb->leftOffset(root()->blockHeight())); if ((extendSelection || endPos > m_start + m_len) && root()->lastLeafChild() == this) maxX = absx + kMin(cb->rightOffset(ty), cb->rightOffset(root()->blockHeight())); f->drawHighlightForText(p, x, minX, maxX, absy + ty, h, text->str->s, text->str->l, m_start, m_len, m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, style->visuallyOrdered(), sPos, ePos, c);#else f->drawHighlightForText(p, m_x + tx, m_y + ty, text->str->s, text->str->l, m_start, m_len, m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, sPos, ePos, c);#endif p->restore();}#ifdef APPLE_CHANGESvoid InlineTextBox::paintDecoration( QPainter *pt, int _tx, int _ty, int deco){ _tx += m_x; _ty += m_y; if (m_truncation == cFullTruncation) return; int width = (m_truncation == cNoTruncation) ? m_width : static_cast<RenderText*>(m_object)->width(m_start, m_truncation - m_start, m_firstLine); // Get the text decoration colors. QColor underline, overline, linethrough; object()->getTextDecorationColors(deco, underline, overline, linethrough, true); // Use a special function for underlines to get the positioning exactly right. if (deco & UNDERLINE) { pt->setPen(underline); pt->drawLineForText(_tx, _ty, m_baseline, width); } if (deco & OVERLINE) { pt->setPen(overline); pt->drawLineForText(_tx, _ty, 0, width); } if (deco & LINE_THROUGH) { pt->setPen(linethrough); pt->drawLineForText(_tx, _ty, 2*m_baseline/3, width); }}#elsevoid InlineTextBox::paintDecoration( QPainter *pt, int _tx, int _ty, int decoration){ _tx += m_x; _ty += m_y; int width = m_width - 1; QColor underline, overline, linethrough; object()->getTextDecorationColors(decoration, underline, overline, linethrough, true); int underlineOffset = ( pt->fontMetrics().height() + m_baseline ) / 2; if(underlineOffset <= m_baseline) underlineOffset = m_baseline+1; if(deco & UNDERLINE){ pt->setPen(underline); pt->drawLine(_tx, _ty + underlineOffset, _tx + width, _ty + underlineOffset ); } if (deco & OVERLINE) { pt->setPen(overline); pt->drawLine(_tx, _ty, _tx + width, _ty ); } if(deco & LINE_THROUGH) { pt->setPen(linethrough); pt->drawLine(_tx, _ty + 2*m_baseline/3, _tx + width, _ty + 2*m_baseline/3 ); } // NO! Do NOT add BLINK! It is the most annouing feature of Netscape, and IE has a reason not to // support it. Lars}#endiflong InlineTextBox::caretMinOffset() const{ return m_start;}long InlineTextBox::caretMaxOffset() const{ return m_start + m_len;}unsigned long InlineTextBox::caretMaxRenderedOffset() const{ return m_start + m_len;}#define LOCAL_WIDTH_BUF_SIZE 1024int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs){ RenderText* text = static_cast<RenderText*>(m_object); const Font* f = text->htmlFont(m_firstLine); return f->checkSelectionPoint(text->str->s, text->str->l, m_start, m_len, m_toAdd, _x - m_x, m_reversed, includePartialGlyphs);}// -------------------------------------------------------------------------------------RenderText::RenderText(DOM::NodeImpl* node, DOMStringImpl *_str) : RenderObject(node), m_linesDirty(false){ // init RenderObject attributes setRenderText(); // our object inherits from RenderText m_minWidth = -1; m_maxWidth = -1;#ifdef APPLE_CHANGES m_monospaceCharacterWidth = 0; m_allAsciiChecked = false; m_allAscii = false;#endif str = _str; if (str) { str = str->replace('\\', backslashAsCurrencySymbol()); str->ref(); } KHTMLAssert(!str || !str->l || str->s); m_firstTextBox = m_lastTextBox = 0; m_selectionState = SelectionNone;#ifdef DEBUG_LAYOUT QConstString cstr(str->s, str->l); kdDebug( 6040 ) << "RenderText ctr( "<< cstr.string().length() << " ) '" << cstr.string() << "'" << endl;#endif}void RenderText::setStyle(RenderStyle *_style){ if ( style() != _style ) { bool needToTransformText = (!style() && _style->textTransform() != TTNONE) || (style() && style()->textTransform() != _style->textTransform()); RenderObject::setStyle( _style ); if (needToTransformText) { DOM::DOMStringImpl* textToTransform = originalString(); if (textToTransform) setText(textToTransform, true); }#if APPLE_CHANGES // setText also calls cacheWidths(), so there is no need to call it again in that case. else cacheWidths();#endif }}RenderText::~RenderText(){ if(str) str->deref();}void RenderText::detach(){ if (!documentBeingDestroyed()) { if (firstTextBox()) for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) box->remove(); else if (parent() && isBR()) parent()->dirtyLinesFromChangedChild(this); } deleteTextBoxes(); RenderObject::detach();}void RenderText::extractTextBox(InlineTextBox* box){ m_lastTextBox = box->prevTextBox(); if (box == m_firstTextBox) m_firstTextBox = 0; if (box->prevTextBox()) box->prevTextBox()->setNextLineBox(0); box->setPreviousLineBox(0); for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox()) curr->setExtracted();}void RenderText::attachTextBox(InlineTextBox* box){ if (m_lastTextBox) { m_lastTextBox->setNextLineBox(box); box->setPreviousLineBox(m_lastTextBox); } else m_firstTextBox = box; InlineTextBox* last = box; for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -