📄 render_text.cpp
字号:
selectionTextShadow = pseudoStyle->textShadow();
}
}
}
if (!paintSelectedTextOnly && !paintSelectedTextSeparately) {
// paint all the text
// FIXME: Handle RTL direction, handle reversed strings. For now truncation can only be turned on
// for non-reversed LTR strings.
int endPoint = m_len;
if (m_truncation != cNoTruncation)
endPoint = m_truncation - m_start;
font->drawText(i.p, m_x + tx, m_y + ty + m_baseline,
textObject()->string()->s, textObject()->string()->l, m_start, endPoint,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered());
} else {
int sPos, ePos;
selectionStartEnd(sPos, ePos);
if (paintSelectedTextSeparately) {
// paint only the text that is not selected
if (sPos >= ePos) {
font->drawText(i.p, m_x + tx, m_y + ty + m_baseline,
textObject()->string()->s, textObject()->string()->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered());
} else {
if (sPos - 1 >= 0) {
font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
textObject()->string()->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), 0, sPos);
}
if (ePos < m_start + m_len) {
font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
textObject()->string()->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), ePos, -1);
}
}
}
if (sPos < ePos) {
// paint only the text that is selected
if (selectionColor != i.p->pen().color())
i.p->setPen(selectionColor);
if (selectionTextShadow)
i.p->setShadow(selectionTextShadow->x,
selectionTextShadow->y,
selectionTextShadow->blur,
selectionTextShadow->color);
font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
textObject()->string()->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), sPos, ePos);
if (selectionTextShadow)
i.p->clearShadow();
}
}
// Paint decorations
if (d != TDNONE && i.phase != PaintActionSelection && styleToUse->htmlHacks()) {
i.p->setPen(styleToUse->color());
paintDecoration(i.p, tx, ty, d);
}
// Draw any doc markers that touch this run
// Note end() points at the last char, not one past it like endOffset and ranges do
if (i.phase != PaintActionSelection) {
for ( ; markerIt != markers.end(); markerIt++) {
DocumentMarker marker = *markerIt;
if (marker.endOffset <= start())
// marker is completely before this run. This might be a marker that sits before the
// first run we draw, or markers that were within runs we skipped due to truncation.
continue;
if (marker.startOffset <= end()) {
// marker intersects this run. Paint it.
paintMarker(i.p, tx, ty, marker);
if (marker.endOffset > end() + 1)
// marker also runs into the next run. Bail now, no more marker advancement.
break;
} else
// marker is completely after this run, bail. A later run will paint it.
break;
}
for ( ; underlineIt != underlines.end(); underlineIt++) {
KWQKHTMLPart::MarkedTextUnderline underline = *underlineIt;
if (underline.endOffset <= start())
// underline is completely before this run. This might be an underlinethat sits
// before the first run we draw, or underlines that were within runs we skipped
// due to truncation.
continue;
if (underline.startOffset <= end()) {
// underline intersects this run. Paint it.
paintMarkedTextUnderline(i.p, tx, ty, underline);
if (underline.endOffset > end() + 1)
// underline also runs into the next run. Bail now, no more marker advancement.
break;
} else
// underline is completely after this run, bail. A later run will paint it.
break;
}
}
if (setShadow)
i.p->clearShadow();
}
void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
{
int startPos, endPos;
if (object()->selectionState() == RenderObject::SelectionInside) {
startPos = 0;
endPos = textObject()->string()->l;
} else {
textObject()->selectionStartEnd(startPos, endPos);
if (object()->selectionState() == RenderObject::SelectionStart)
endPos = textObject()->string()->l;
else if (object()->selectionState() == RenderObject::SelectionEnd)
startPos = 0;
}
sPos = kMax(startPos - m_start, 0);
ePos = kMin(endPos - m_start, (int)m_len);
}
void InlineTextBox::paintSelection(QPainter* p, int tx, int ty, RenderStyle* style, const Font* f)
{
// See if we have a selection to paint at all.
int sPos, ePos;
selectionStartEnd(sPos, ePos);
if (sPos >= ePos)
return;
// Macintosh-style text highlighting is to draw with a particular background color, not invert.
QColor textColor = style->color();
QColor c = object()->selectionColor(p);
if (!c.isValid())
return;
// If the text color ends up being the same as the selection background, invert the selection
// background. This should basically never happen, since the selection has transparency.
if (textColor == c)
c = QColor(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
p->save();
p->setPen(c); // Don't draw text at all!
RootInlineBox* r = root();
int x = m_x + tx;
int y = r->selectionTop();
int h = r->selectionHeight();
f->drawHighlightForText(p, x, y + ty, h,
textObject()->str->s, textObject()->str->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, style->visuallyOrdered(), sPos, ePos, c);
p->restore();
}
void InlineTextBox::paintMarkedTextBackground(QPainter* p, int tx, int ty, RenderStyle* style, const Font* f, int startPos, int endPos)
{
int offset = m_start;
int sPos = kMax(startPos - offset, 0);
int ePos = kMin(endPos - offset, (int)m_len);
if (sPos >= ePos)
return;
p->save();
QColor c = QColor(225, 221, 85);
p->setPen(c); // Don't draw text at all!
RootInlineBox* r = root();
int x = m_x + tx;
int y = r->selectionTop();
int h = r->selectionHeight();
f->drawHighlightForText(p, x, y + ty, h, textObject()->str->s, textObject()->str->l, m_start, m_len,
m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, style->visuallyOrdered(), sPos, ePos, c);
p->restore();
}
void 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);
}
}
void InlineTextBox::paintMarker(QPainter *pt, int _tx, int _ty, DocumentMarker marker)
{
#if !NOKIA_CHANGES
_tx += m_x;
_ty += m_y;
if (m_truncation == cFullTruncation)
return;
int start = 0; // start of line to draw, relative to _tx
int width = m_width; // how much line to draw
bool useWholeWidth = true;
ulong paintStart = m_start;
ulong paintEnd = end()+1; // end points at the last char, not past it
if (paintStart <= marker.startOffset) {
paintStart = marker.startOffset;
useWholeWidth = false;
start = static_cast<RenderText*>(m_object)->width(m_start, paintStart - m_start, m_firstLine);
}
if (paintEnd != marker.endOffset) { // end points at the last char, not past it
paintEnd = kMin(paintEnd, marker.endOffset);
useWholeWidth = false;
}
if (m_truncation != cNoTruncation) {
paintEnd = kMin(paintEnd, (ulong)m_truncation);
useWholeWidth = false;
}
if (!useWholeWidth) {
width = static_cast<RenderText*>(m_object)->width(paintStart, paintEnd - paintStart, m_firstLine);
}
// IMPORTANT: The misspelling underline is not considered when calculating the text bounds, so we have to
// make sure to fit within those bounds. This means the top pixel(s) of the underline will overlap the
// bottom pixel(s) of the glyphs in smaller font sizes. The alternatives are to increase the line spacing (bad!!)
// or decrease the underline thickness. The overlap is actually the most useful, and matches what AppKit does.
// So, we generally place the underline at the bottom of the text, but in larger fonts that's not so good so
// we pin to two pixels under the baseline.
int lineThickness = pt->misspellingLineThickness();
int descent = m_height - m_baseline;
int underlineOffset;
if (descent <= (2 + lineThickness)) {
// place the underline at the very bottom of the text in small/medium fonts
underlineOffset = m_height - lineThickness;
} else {
// in larger fonts, tho, place the underline up near the baseline to prevent big gap
underlineOffset = m_baseline + 2;
}
pt->drawLineForMisspelling(_tx + start, _ty + underlineOffset, width);
#endif
}
void InlineTextBox::paintMarkedTextUnderline(QPainter *pt, int _tx, int _ty, KWQKHTMLPart::MarkedTextUnderline underline)
{
_tx += m_x;
_ty += m_y;
if (m_truncation == cFullTruncation)
return;
int start = 0; // start of line to draw, relative to _tx
int width = m_width; // how much line to draw
bool useWholeWidth = true;
ulong paintStart = m_start;
ulong paintEnd = end()+1; // end points at the last char, not past it
if (paintStart <= underline.startOffset) {
paintStart = underline.startOffset;
useWholeWidth = false;
start = static_cast<RenderText*>(m_object)->width(m_start, paintStart - m_start, m_firstLine);
}
if (paintEnd != underline.endOffset) { // end points at the last char, not past it
paintEnd = kMin(paintEnd, (ulong)underline.endOffset);
useWholeWidth = false;
}
if (m_truncation != cNoTruncation) {
paintEnd = kMin(paintEnd, (ulong)m_truncation);
useWholeWidth = false;
}
if (!useWholeWidth) {
width = static_cast<RenderText*>(m_object)->width(paintStart, paintEnd - paintStart, m_firstLine);
}
int underlineOffset = m_height - 3;
pt->setPen(QPen(underline.color, underline.thick ? 2 : 0));
pt->drawLineForText(_tx + start, _ty, underlineOffset, width);
}
long 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;
}
#if HAVE_ICU_LIBRARY
static UBreakIterator *getCharacterBreakIterator(const DOMStringImpl *i)
{
// The locale is currently ignored when determining character cluster breaks. This may change
// in the future (according to Deborah Goldsmith).
static bool createdIterator = false;
static UBreakIterator *iterator;
UErrorCode status;
if (!createdIterator) {
status = U_ZERO_ERROR;
iterator = ubrk_open(UBRK_CHARACTER, "en_us", NULL, 0, &status);
createdIterator = true;
}
if (!iterator) {
return NULL;
}
status = U_ZERO_ERROR;
ubrk_setText(iterator, reinterpret_cast<const UChar *>(i->s), i->l, &status);
if (status != U_ZERO_ERROR) {
return NULL;
}
return iterator;
}
#endif
long RenderText::previousOffset (long current) const
{
#if HAVE_ICU_LIBRARY
UBreakIterator *iterator = getCharacterBreakIterator(str);
if (iterator) {
return ubrk_preceding(iterator, current);
}
#endif
return current - 1;
}
long RenderText::nextOffset (long current) const
{
#if HAVE_ICU_LIBRARY
UBreakIterator *iterator = getCharacterBreakIterator(str);
if (iterator) {
return ubrk_following(iterator, current);
}
#endif
return current + 1;
}
#define LOCAL_WIDTH_BUF_SIZE 1024
int 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);
}
// -------------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -