📄 rendertext.cpp
字号:
return prev;}void RenderText::setTextInternal(PassRefPtr<StringImpl> text){ m_text = text; ASSERT(m_text); m_text = document()->displayStringModifiedByEncoding(PassRefPtr<StringImpl>(m_text));#if ENABLE(SVG) if (isSVGText()) { if (style() && style()->whiteSpace() == PRE) { // Spec: When xml:space="preserve", the SVG user agent will do the following using a // copy of the original character data content. It will convert all newline and tab // characters into space characters. Then, it will draw all space characters, including // leading, trailing and multiple contiguous space characters. m_text = m_text->replace('\n', ' '); // If xml:space="preserve" is set, white-space is set to "pre", which // preserves leading, trailing & contiguous space character for us. } else { // Spec: When xml:space="default", the SVG user agent will do the following using a // copy of the original character data content. First, it will remove all newline // characters. Then it will convert all tab characters into space characters. // Then, it will strip off all leading and trailing space characters. // Then, all contiguous space characters will be consolidated. m_text = m_text->replace('\n', StringImpl::empty()); // If xml:space="default" is set, white-space is set to "nowrap", which handles // leading, trailing & contiguous space character removal for us. } m_text = m_text->replace('\t', ' '); }#endif if (style()) { switch (style()->textTransform()) { case TTNONE: break; case CAPITALIZE: { m_text = m_text->capitalize(previousCharacter()); break; } case UPPERCASE: m_text = m_text->upper(); break; case LOWERCASE: m_text = m_text->lower(); break; } // We use the same characters here as for list markers. // See the listMarkerText function in RenderListMarker.cpp. switch (style()->textSecurity()) { case TSNONE: break; case TSCIRCLE: m_text = m_text->secure(whiteBullet); break; case TSDISC: m_text = m_text->secure(bullet); break; case TSSQUARE: m_text = m_text->secure(blackSquare); } } ASSERT(m_text); ASSERT(!isBR() || (textLength() == 1 && (*m_text)[0] == '\n')); m_isAllASCII = charactersAreAllASCII(m_text.get());}void RenderText::setText(PassRefPtr<StringImpl> text, bool force){ ASSERT(text); if (!force && equal(m_text.get(), text.get())) return; setTextInternal(text); setNeedsLayoutAndPrefWidthsRecalc();}int RenderText::lineHeight(bool firstLine, bool) const{ // Always use the interior line height of the parent (e.g., if our parent is an inline block). return parent()->lineHeight(firstLine, true);}void RenderText::dirtyLineBoxes(bool fullLayout){ if (fullLayout) deleteTextBoxes(); else if (!m_linesDirty) { for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) box->dirtyLineBoxes(); } m_linesDirty = false;}InlineTextBox* RenderText::createTextBox(){ return new (renderArena()) InlineTextBox(this);}InlineTextBox* RenderText::createInlineTextBox(){ InlineTextBox* textBox = createTextBox(); if (!m_firstTextBox) m_firstTextBox = m_lastTextBox = textBox; else { m_lastTextBox->setNextLineBox(textBox); textBox->setPreviousLineBox(m_lastTextBox); m_lastTextBox = textBox; } return textBox;}void RenderText::positionLineBox(InlineBox* box){ InlineTextBox* s = static_cast<InlineTextBox*>(box); // FIXME: should not be needed!!! if (!s->len()) { // We want the box to be destroyed. s->remove(); s->destroy(renderArena()); m_firstTextBox = m_lastTextBox = 0; return; } m_containsReversedText |= s->direction() == RTL;}unsigned RenderText::width(unsigned from, unsigned len, int xPos, bool firstLine) const{ if (from >= textLength()) return 0; if (from + len > textLength()) len = textLength() - from; return width(from, len, style(firstLine)->font(), xPos);}unsigned RenderText::width(unsigned from, unsigned len, const Font& f, int xPos) const{ ASSERT(from + len <= textLength()); if (!characters()) return 0; int w; if (&f == &style()->font()) { if (!style()->preserveNewline() && !from && len == textLength()) w = maxPrefWidth(); else w = widthFromCache(f, from, len, xPos); } else w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos)); return w;}IntRect RenderText::linesBoundingBox() const{ IntRect result; ASSERT(!firstTextBox() == !lastTextBox()); // Either both are null or both exist. if (firstTextBox() && lastTextBox()) { // Return the width of the minimal left side and the maximal right side. int leftSide = 0; int rightSide = 0; for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) { if (curr == firstTextBox() || curr->x() < leftSide) leftSide = curr->x(); if (curr == firstTextBox() || curr->x() + curr->width() > rightSide) rightSide = curr->x() + curr->width(); } result.setWidth(rightSide - leftSide); result.setX(leftSide); result.setHeight(lastTextBox()->y() + lastTextBox()->height() - firstTextBox()->y()); result.setY(firstTextBox()->y()); } return result;}IntRect RenderText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer){ RenderObject* cb = containingBlock(); return cb->clippedOverflowRectForRepaint(repaintContainer);}IntRect RenderText::selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent){ ASSERT(!needsLayout()); if (selectionState() == SelectionNone) return IntRect(); RenderBlock* cb = containingBlock(); if (!cb) return IntRect(); // Now calculate startPos and endPos for painting selection. // We include a selection while endPos > 0 int startPos, endPos; if (selectionState() == SelectionInside) { // We are fully selected. startPos = 0; endPos = textLength(); } else { selectionStartEnd(startPos, endPos); if (selectionState() == SelectionStart) endPos = textLength(); else if (selectionState() == SelectionEnd) startPos = 0; } if (startPos == endPos) return IntRect(); IntRect rect; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) rect.unite(box->selectionRect(0, 0, startPos, endPos)); if (clipToVisibleContent) computeRectForRepaint(repaintContainer, rect); else { if (cb->hasColumns()) cb->adjustRectForColumns(rect); rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox(); } return rect;}int RenderText::caretMinOffset() const{ InlineTextBox* box = firstTextBox(); if (!box) return 0; int minOffset = box->start(); for (box = box->nextTextBox(); box; box = box->nextTextBox()) minOffset = min<int>(minOffset, box->start()); return minOffset;}int RenderText::caretMaxOffset() const{ InlineTextBox* box = lastTextBox(); if (!box) return textLength(); int maxOffset = box->start() + box->len(); for (box = box->prevTextBox(); box; box = box->prevTextBox()) maxOffset = max<int>(maxOffset, box->start() + box->len()); return maxOffset;}unsigned RenderText::caretMaxRenderedOffset() const{ int l = 0; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) l += box->len(); return l;}int RenderText::previousOffset(int current) const{ StringImpl* si = m_text.get(); TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length()); if (!iterator) return current - 1; long result = textBreakPreceding(iterator, current); if (result == TextBreakDone) result = current - 1;#ifdef BUILDING_ON_TIGER // ICU 3.2 allows character breaks before a half-width Katakana voiced mark. if (static_cast<unsigned>(result) < si->length()) { UChar character = (*si)[result]; if (character == 0xFF9E || character == 0xFF9F) --result; }#endif return result;}#define HANGUL_CHOSEONG_START (0x1100)#define HANGUL_CHOSEONG_END (0x115F)#define HANGUL_JUNGSEONG_START (0x1160)#define HANGUL_JUNGSEONG_END (0x11A2)#define HANGUL_JONGSEONG_START (0x11A8)#define HANGUL_JONGSEONG_END (0x11F9)#define HANGUL_SYLLABLE_START (0xAC00)#define HANGUL_SYLLABLE_END (0xD7AF)#define HANGUL_JONGSEONG_COUNT (28)enum HangulState { HangulStateL, HangulStateV, HangulStateT, HangulStateLV, HangulStateLVT, HangulStateBreak};inline bool isHangulLVT(UChar32 character){ return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;}int RenderText::previousOffsetForBackwardDeletion(int current) const{#if PLATFORM(MAC) UChar32 character; while (current > 0) { if (U16_IS_TRAIL((*m_text)[--current])) --current; if (current < 0) break; UChar32 character = m_text->characterStartingAt(current); // We don't combine characters in Armenian ... Limbu range for backward deletion. if ((character >= 0x0530) && (character < 0x1950)) break; if (u_isbase(character) && (character != 0xFF9E) && (character != 0xFF9F)) break; } if (current <= 0) return current; // Hangul character = m_text->characterStartingAt(current); if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) { HangulState state; HangulState initialState; if (character < HANGUL_JUNGSEONG_START) state = HangulStateL; else if (character < HANGUL_JONGSEONG_START) state = HangulStateV; else if (character < HANGUL_SYLLABLE_START) state = HangulStateT; else state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV; initialState = state; while (current > 0 && ((character = m_text->characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) { switch (state) { case HangulStateV: if (character <= HANGUL_CHOSEONG_END) state = HangulStateL; else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character)) state = HangulStateLV; else if (character > HANGUL_JUNGSEONG_END) state = HangulStateBreak; break; case HangulStateT: if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END)) state = HangulStateV; else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END)) state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV); else if (character < HANGUL_JUNGSEONG_START) state = HangulStateBreak; break; default: state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak; break; } if (state == HangulStateBreak) break; --current; } } return current;#else // Platforms other than Mac delete by one code point. return current - 1;#endif}int RenderText::nextOffset(int current) const{ StringImpl* si = m_text.get(); TextBreakIterator* iterator = cursorMovementIterator(si->characters(), si->length()); if (!iterator) return current + 1; long result = textBreakFollowing(iterator, current); if (result == TextBreakDone) result = current + 1;#ifdef BUILDING_ON_TIGER // ICU 3.2 allows character breaks before a half-width Katakana voiced mark. if (static_cast<unsigned>(result) < si->length()) { UChar character = (*si)[result]; if (character == 0xFF9E || character == 0xFF9F) ++result; }#endif return result;}#ifndef NDEBUGvoid RenderText::checkConsistency() const{#ifdef CHECK_CONSISTENCY const InlineTextBox* prev = 0; for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) { ASSERT(child->object() == this); ASSERT(child->prevTextBox() == prev); prev = child; } ASSERT(prev == m_lastTextBox);#endif}#endif} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -