📄 inlinetextbox.cpp
字号:
if (shadow) { if (!shadow->next) { // The last set of lines paints normally inside the clip. ty -= extraOffset; extraOffset = 0; } context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color); setShadow = true; shadow = shadow->next; } if (deco & UNDERLINE) { context->setStrokeColor(underline); context->setStrokeStyle(SolidStroke); // Leave one pixel of white between the baseline and the underline. context->drawLineForText(IntPoint(tx, ty + baseline + 1), width, isPrinting); } if (deco & OVERLINE) { context->setStrokeColor(overline); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty), width, isPrinting); } if (deco & LINE_THROUGH) { context->setStrokeColor(linethrough); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty + 2 * baseline / 3), width, isPrinting); } } while (shadow); if (setClip) context->restore(); else if (setShadow) context->clearShadow();}void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font, bool grammar){ // Never print spelling/grammar markers (5327887) if (textRenderer()->document()->printing()) return; 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 // Determine whether we need to measure text bool markerSpansWholeBox = true; if (m_start <= (int)marker.startOffset) markerSpansWholeBox = false; if ((end() + 1) != marker.endOffset) // end points at the last char, not past it markerSpansWholeBox = false; if (m_truncation != cNoTruncation) markerSpansWholeBox = false; if (!markerSpansWholeBox || grammar) { int startPosition = max<int>(marker.startOffset - m_start, 0); int endPosition = min<int>(marker.endOffset - m_start, m_len); if (m_truncation != cNoTruncation) endPosition = min<int>(endPosition, m_truncation); // Calculate start & width IntPoint startPoint(tx + m_x, ty + selectionTop()); TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); int h = selectionHeight(); IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, startPosition, endPosition)); start = markerRect.x() - startPoint.x(); width = markerRect.width(); // Store rendered rects for bad grammar markers, so we can hit-test against it elsewhere in order to // display a toolTip. We don't do this for misspelling markers. if (grammar) renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); } // 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 = cMisspellingLineThickness; int baseline = renderer()->style(m_firstLine)->font().ascent(); int descent = height() - baseline; int underlineOffset; if (descent <= (2 + lineThickness)) { // Place the underline at the very bottom of the text in small/medium fonts. underlineOffset = height() - lineThickness; } else { // In larger fonts, though, place the underline up near the baseline to prevent a big gap. underlineOffset = baseline + 2; } pt->drawLineForMisspellingOrBadGrammar(IntPoint(tx + m_x + start, ty + m_y + underlineOffset), width, grammar);}void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font& font){ // Use same y positioning and height as for selection, so that when the selection and this highlight are on // the same word there are no pieces sticking out. int y = selectionTop(); int h = selectionHeight(); int sPos = max(marker.startOffset - m_start, (unsigned)0); int ePos = min(marker.endOffset - m_start, (unsigned)m_len); TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); IntPoint startPoint = IntPoint(m_x + tx, y + ty); // Always compute and store the rect associated with this marker IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, h, sPos, ePos)); renderer()->document()->setRenderedRectForMarker(renderer()->node(), marker, markerRect); // Optionally highlight the text if (renderer()->document()->frame()->markedTextMatchesAreHighlighted()) { Color color = theme()->platformTextSearchHighlightColor(); pt->save(); updateGraphicsContext(pt, color, color, 0); // Don't draw text at all! pt->clip(IntRect(tx + m_x, ty + y, m_width, h)); pt->drawHighlightForText(font, run, startPoint, h, color, sPos, ePos); pt->restore(); }}void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, RenderStyle* style, const Font& font, bool background){ if (!renderer()->node()) return; Vector<DocumentMarker> markers = renderer()->document()->markersForNode(renderer()->node()); Vector<DocumentMarker>::iterator markerIt = markers.begin(); // Give any document markers that touch this run a chance to draw before the text has been drawn. // Note end() points at the last char, not one past it like endOffset and ranges do. for ( ; markerIt != markers.end(); markerIt++) { DocumentMarker marker = *markerIt; // Paint either the background markers or the foreground markers, but not both switch (marker.type) { case DocumentMarker::Grammar: case DocumentMarker::Spelling: if (background) continue; break; case DocumentMarker::TextMatch: if (!background) continue; break; default: ASSERT_NOT_REACHED(); } 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 is completely after this run, bail. A later run will paint it. break; // marker intersects this run. Paint it. switch (marker.type) { case DocumentMarker::Spelling: paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, font, false); break; case DocumentMarker::Grammar: paintSpellingOrGrammarMarker(pt, tx, ty, marker, style, font, true); break; case DocumentMarker::TextMatch: paintTextMatchMarker(pt, tx, ty, marker, style, font); break; default: ASSERT_NOT_REACHED(); } }}void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int ty, const CompositionUnderline& 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; unsigned paintStart = m_start; unsigned paintEnd = end() + 1; // end points at the last char, not past it if (paintStart <= underline.startOffset) { paintStart = underline.startOffset; useWholeWidth = false; start = toRenderText(renderer())->width(m_start, paintStart - m_start, textPos(), m_firstLine); } if (paintEnd != underline.endOffset) { // end points at the last char, not past it paintEnd = min(paintEnd, (unsigned)underline.endOffset); useWholeWidth = false; } if (m_truncation != cNoTruncation) { paintEnd = min(paintEnd, (unsigned)m_start + m_truncation); useWholeWidth = false; } if (!useWholeWidth) { width = toRenderText(renderer())->width(paintStart, paintEnd - paintStart, textPos() + start, m_firstLine); } // Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline. // All other marked text underlines are 1px thick. // If there's not enough space the underline will touch or overlap characters. int lineThickness = 1; int baseline = renderer()->style(m_firstLine)->font().ascent(); if (underline.thick && height() - baseline >= 2) lineThickness = 2; // We need to have some space between underlines of subsequent clauses, because some input methods do not use different underline styles for those. // We make each line shorter, which has a harmless side effect of shortening the first and last clauses, too. start += 1; width -= 2; ctx->setStrokeColor(underline.color); ctx->setStrokeThickness(lineThickness); ctx->drawLineForText(IntPoint(tx + start, ty + height() - lineThickness), width, textRenderer()->document()->printing());}int InlineTextBox::caretMinOffset() const{ return m_start;}int InlineTextBox::caretMaxOffset() const{ return m_start + m_len;}unsigned InlineTextBox::caretMaxRenderedOffset() const{ return m_start + m_len;}int InlineTextBox::textPos() const{ if (x() == 0) return 0; RenderBlock *blockElement = renderer()->containingBlock(); return direction() == RTL ? x() - blockElement->borderRight() - blockElement->paddingRight() : x() - blockElement->borderLeft() - blockElement->paddingLeft();}int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const{ if (isLineBreak()) return 0; RenderText* text = toRenderText(renderer()); RenderStyle *style = text->style(m_firstLine); const Font* f = &style->font(); return f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), _x - m_x, includePartialGlyphs);}int InlineTextBox::positionForOffset(int offset) const{ ASSERT(offset >= m_start); ASSERT(offset <= m_start + m_len); if (isLineBreak()) return m_x; RenderText* text = toRenderText(renderer()); const Font& f = text->style(m_firstLine)->font(); int from = direction() == RTL ? offset - m_start : 0; int to = direction() == RTL ? m_len : offset - m_start; // FIXME: Do we need to add rightBearing here? return enclosingIntRect(f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride), IntPoint(m_x, 0), 0, from, to)).right();}bool InlineTextBox::containsCaretOffset(int offset) const{ // Offsets before the box are never "in". if (offset < m_start) return false; int pastEnd = m_start + m_len; // Offsets inside the box (not at either edge) are always "in". if (offset < pastEnd) return true; // Offsets outside the box are always "out". if (offset > pastEnd) return false; // Offsets at the end are "out" for line breaks (they are on the next line). if (isLineBreak()) return false; // Offsets at the end are "in" for normal boxes (but the caller has to check affinity). return true;}} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -