void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font* f) { // 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(textObject()->text()->characters() + m_start, m_len, textObject()->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(f->selectionRectForText(run, startPoint, h, sPos, ePos)); object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect); // Optionally highlight the text if (object()->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(run, startPoint, h, color, sPos, ePos); pt->restore(); } }
void InlineTextBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font*) { // See if we have a selection to paint at all. int sPos, ePos; selectionStartEnd(sPos, ePos); if (sPos >= ePos) return; Color textColor = style->color(); Color c = object()->selectionBackgroundColor(); if (!c.isValid() || c.alpha() == 0) 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 = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); context->save(); updateGraphicsContext(context, c, c, 0); // Don't draw text at all! int y = selectionTop(); int h = selectionHeight(); context->clip(IntRect(m_x + tx, y + ty, m_width, h)); context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); context->restore(); }
void RootInlineBox::addHighlightOverflow() { // Highlight acts as a selection inflation. FloatRect rootRect(0, selectionTop(), width(), selectionHeight()); IntRect inflatedRect = enclosingIntRect(object()->document()->frame()->customHighlightLineRect(object()->style()->highlight(), rootRect)); m_leftOverflow = min(m_leftOverflow, inflatedRect.x()); m_rightOverflow = max(m_rightOverflow, inflatedRect.right()); m_topOverflow = min(m_topOverflow, inflatedRect.y()); m_bottomOverflow = max(m_bottomOverflow, inflatedRect.bottom()); }
void RootInlineBox::paintCustomHighlight(RenderObject::PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType) { if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; // Get the inflated rect so that we can properly hit test. FloatRect rootRect(tx + xPos(), ty + selectionTop(), width(), selectionHeight()); FloatRect inflatedRect = object()->document()->frame()->customHighlightLineRect(highlightType, rootRect); if (inflatedRect.intersects(paintInfo.rect)) object()->document()->frame()->paintCustomHighlight(highlightType, rootRect, rootRect, false, true); }
IntRect RootInlineBox::computeCaretRect(float logicalLeftPosition, unsigned caretWidth, LayoutUnit* extraWidthToEndOfLine) const { int height = selectionHeight(); int top = selectionTop(); // Distribute the caret's width to either side of the offset. float left = logicalLeftPosition; int caretWidthLeftOfOffset = caretWidth / 2; left -= caretWidthLeftOfOffset; int caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset; left = roundf(left); float rootLeft = logicalLeft(); float rootRight = logicalRight(); if (extraWidthToEndOfLine) *extraWidthToEndOfLine = (logicalWidth() + rootLeft) - (left + caretWidth); const RenderStyle& blockStyle = blockFlow().style(); bool rightAligned = false; switch (blockStyle.textAlign()) { case RIGHT: case WEBKIT_RIGHT: rightAligned = true; break; case LEFT: case WEBKIT_LEFT: case CENTER: case WEBKIT_CENTER: break; case JUSTIFY: case TASTART: rightAligned = !blockStyle.isLeftToRightDirection(); break; case TAEND: rightAligned = blockStyle.isLeftToRightDirection(); break; } float leftEdge = std::min<float>(0, rootLeft); float rightEdge = std::max<float>(blockFlow().logicalWidth(), rootRight); if (rightAligned) { left = std::max(left, leftEdge); left = std::min(left, rootRight - caretWidth); } else { left = std::min(left, rightEdge - caretWidthRightOfOffset); left = std::max(left, rootLeft); } return blockStyle.isHorizontalWritingMode() ? IntRect(left, top, caretWidth, height) : IntRect(top, left, height, caretWidth); }
void RootInlineBox::addHighlightOverflow() { Frame* frame = renderer()->document()->frame(); if (!frame) return; Page* page = frame->page(); if (!page) return; // Highlight acts as a selection inflation. FloatRect rootRect(0, selectionTop(), width(), selectionHeight()); IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(renderer()->node(), renderer()->style()->highlight(), rootRect)); setHorizontalOverflowPositions(leftLayoutOverflow(), rightLayoutOverflow(), min(leftVisualOverflow(), inflatedRect.x()), max(rightVisualOverflow(), inflatedRect.right())); setVerticalOverflowPositions(topLayoutOverflow(), bottomLayoutOverflow(), min(topVisualOverflow(), inflatedRect.y()), max(bottomVisualOverflow(), inflatedRect.bottom()), height()); }
void InlineTextBox::paintCustomHighlight(int tx, int ty, const AtomicString& type) { Frame* frame = object()->document()->frame(); if (!frame) return; Page* page = frame->page(); if (!page) return; RootInlineBox* r = root(); FloatRect rootRect(tx + r->xPos(), ty + selectionTop(), r->width(), selectionHeight()); FloatRect textRect(tx + xPos(), rootRect.y(), width(), rootRect.height()); page->chrome()->client()->paintCustomHighlight(object()->node(), type, textRect, rootRect, true, false); }
void RootInlineBox::paintCustomHighlight(RenderObject::PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType) { if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; Frame* frame = renderer()->document()->frame(); if (!frame) return; Page* page = frame->page(); if (!page) return; // Get the inflated rect so that we can properly hit test. FloatRect rootRect(tx + x(), ty + selectionTop(), width(), selectionHeight()); FloatRect inflatedRect = page->chrome()->client()->customHighlightRect(renderer()->node(), highlightType, rootRect); if (inflatedRect.intersects(paintInfo.rect)) page->chrome()->client()->paintCustomHighlight(renderer()->node(), highlightType, rootRect, rootRect, false, true); }
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 = textObject(); 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::paintCompositionBackground(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font*, int startPos, int endPos) { int offset = m_start; int sPos = max(startPos - offset, 0); int ePos = min(endPos - offset, (int)m_len); if (sPos >= ePos) return; context->save(); Color c = Color(225, 221, 85); updateGraphicsContext(context, c, c, 0); // Don't draw text at all! int y = selectionTop(); int h = selectionHeight(); context->drawHighlightForText(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()), IntPoint(m_x + tx, y + ty), h, c, sPos, ePos); context->restore(); }
void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, int ty, DocumentMarker marker, RenderStyle* style, const Font* f, bool grammar) { // Never print spelling/grammar markers (5327887) if (textObject()->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(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()); int h = selectionHeight(); IntRect markerRect = enclosingIntRect(f->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) object()->document()->setRenderedRectForMarker(object()->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 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->drawLineForMisspellingOrBadGrammar(IntPoint(tx + m_x + start, ty + m_y + underlineOffset), width, grammar); }