示例#1
0
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();
    }
}
示例#2
0
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();
}
示例#3
0
void TestRTFAText::TestReadTokenSequence_rtl()
{
	ComparisonContext cContext;
	RTFFileContext context;
	RTFatext_rtl textObject(&context);
	CTestOnlyRFTParser theParser(&context);	
	CTestOnlyRTFInputFile TheTest("\\rtlch\\af37\\ltrch\\af27");
	
	theParser.SetFile(&TheTest);

	assertTest(theParser.GetToken() == rtfcw_rtlch);
	assertTest(textObject.AcceptsToken(rtfcw_rtlch));
	assertTest(textObject.ReadToken(rtfcw_rtlch, &theParser) == rtfec_OK);

	assertTest(theParser.GetToken() == rtfcw_af);
	assertTest(textObject.AcceptsToken(rtfcw_af));
	assertTest(textObject.ReadToken(rtfcw_af, &theParser) == rtfec_OK);

	assertTest(theParser.GetToken() == rtfcw_ltrch);
	assertTest(textObject.AcceptsToken(rtfcw_ltrch));
	assertTest(textObject.ReadToken(rtfcw_ltrch, &theParser) == rtfec_OK);

	assertTest(theParser.GetToken() == rtfcw_af);
	assertTest(textObject.AcceptsToken(rtfcw_af));
	assertTest(textObject.ReadToken(rtfcw_af, &theParser) == rtfec_OK);

	assertTest(textObject.m_iTok1 == tok_rtlrun);
	assertTest(textObject.m_iTok2 == tok_ltrrun);
	
	assertTest(textObject.m_iAf1 == 37);
	assertTest(textObject.m_iAf2 == 27);
	
	assertTest(textObject.m_b1sf == false);
	assertTest(textObject.m_b2sf == false);
}
示例#4
0
void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
{
    int startPos, endPos;
    if (object()->selectionState() == RenderObject::SelectionInside) {
        startPos = 0;
        endPos = textObject()->textLength();
    } else {
        textObject()->selectionStartEnd(startPos, endPos);
        if (object()->selectionState() == RenderObject::SelectionStart)
            endPos = textObject()->textLength();
        else if (object()->selectionState() == RenderObject::SelectionEnd)
            startPos = 0;
    }

    sPos = max(startPos - m_start, 0);
    ePos = min(endPos - m_start, (int)m_len);
}
void tst_QTextObject::testStandAloneTextObject()
{
    QTextDocument document;
    TestTextObject textObject(&document);

    QCOMPARE(textObject.document(), &document);
    // don't crash
    textObject.format();
    textObject.formatIndex();
    QCOMPARE(textObject.objectIndex(), -1);
}
示例#6
0
int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
{
    if (isLineBreak())
        return 0;

    RenderText* text = static_cast<RenderText*>(m_object);
    RenderStyle *style = text->style(m_firstLine);
    const Font* f = &style->font();
    return f->offsetForPosition(TextRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || style->visuallyOrdered()),
                                _x - m_x, includePartialGlyphs);
}
示例#7
0
void TestRTFAText::TestReadTokenSequence_xxch()
{
	ComparisonContext cContext;
	RTFFileContext context;
	RTFatext_xxch textObject(&context);
	CTestOnlyRFTParser theParser(&context);	
	CTestOnlyRTFInputFile TheTest("\\hich\\af37\\loch\\af27\\dbch\\f17");
	
	
	theParser.SetFile(&TheTest);
	theParser.SetDoubleChars(true);

	assertTest(theParser.GetToken() == rtfcw_hich);
	assertTest(textObject.AcceptsToken(rtfcw_hich));
	assertTest(textObject.ReadToken(rtfcw_hich, &theParser) == rtfec_OK);
	assertTest(!theParser.IsInDoubleChars());

	assertTest(theParser.GetToken() == rtfcw_af);
	assertTest(textObject.AcceptsToken(rtfcw_af));
	assertTest(textObject.ReadToken(rtfcw_af, &theParser) == rtfec_OK);

	assertTest(theParser.GetToken() == rtfcw_loch);
	assertTest(textObject.AcceptsToken(rtfcw_loch));
	assertTest(textObject.ReadToken(rtfcw_loch, &theParser) == rtfec_OK);
	assertTest(!theParser.IsInDoubleChars());

	assertTest(theParser.GetToken() == rtfcw_af);
	assertTest(textObject.AcceptsToken(rtfcw_af));
	assertTest(textObject.ReadToken(rtfcw_af, &theParser) == rtfec_OK);

	assertTest(theParser.GetToken() == rtfcw_dbch);
	assertTest(textObject.AcceptsToken(rtfcw_dbch));
	assertTest(textObject.ReadToken(rtfcw_dbch, &theParser) == rtfec_OK);
	assertTest(theParser.IsInDoubleChars());

	assertTest(theParser.GetToken() == rtfcw_f);
	assertTest(textObject.AcceptsToken(rtfcw_f));
	assertTest(textObject.ReadToken(rtfcw_f, &theParser) == rtfec_OK);
	
	assertTest(textObject.m_iTok1 == tok_hich);
	assertTest(textObject.m_iTok2 == tok_loch);
	assertTest(textObject.m_iTok3 == tok_dbch);
	
	assertTest(textObject.m_iAf1 == 37);
	assertTest(textObject.m_iAf2 == 27);
	assertTest(textObject.m_iAf3 == 17);
	
	assertTest(textObject.m_b1sf == false);
	assertTest(textObject.m_b2sf == false);
	assertTest(textObject.m_b3sf == true);
}
示例#8
0
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 = static_cast<RenderText*>(m_object)->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 = static_cast<RenderText*>(m_object)->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;
    if (underline.thick && m_height - m_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 + m_height - lineThickness), width, textObject()->document()->printing());
}
示例#9
0
void TestRTFAText::TestInitialisation_rtl()
{
	ComparisonContext cContext;
	RTFFileContext context;
	RTFatext_rtl textObject(&context);

	assertTest(textObject.m_iTok1 == tok_rtl_none);
	assertTest(textObject.m_iTok2 == tok_rtl_none);

	assertTest(textObject.m_iAf1 == -1);
	assertTest(textObject.m_iAf2 == -1);

	assertTest(textObject.m_b1sf == false);
	assertTest(textObject.m_b2sf == false);
	
	assertTest(textObject.m_pAprops1 == NULL);
	assertTest(textObject.m_pAprops2 == NULL);
}
示例#10
0
void TestRTFAText::TestWrite_rtl()
{
	ComparisonContext cContext;
	RTFFileContext context;
	RTFatext_rtl textObject(&context);

	CTestOnlyRTFWriter fakeWriter(&context);

	textObject.m_iTok1 = tok_rtlrun;
	textObject.m_iTok2 = tok_ltrrun;
	
	textObject.m_iAf1 = 37;
	textObject.m_iAf2 = 27;
	
	textObject.m_b1sf = false;
	textObject.m_b2sf = false;
	
	textObject.Write(&fakeWriter);
	assertTest(fakeWriter.m_csBuf == "\\rtlch\\af37\\ltrch\\af27");
}
示例#11
0
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();
}
示例#12
0
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;
}
示例#13
0
void TestRTFAText::TestWrite_xxch()
{
	ComparisonContext cContext;
	RTFFileContext context;
	RTFatext_xxch textObject(&context);
	CTestOnlyRTFWriter fakeWriter(&context);

	textObject.m_iTok1 = tok_hich;
	textObject.m_iTok2 = tok_loch;
	textObject.m_iTok3 = tok_dbch;
	
	textObject.m_iAf1 = 37;
	textObject.m_iAf2 = 27;
	textObject.m_iAf3 = 17;
	
	textObject.m_b1sf = false;
	textObject.m_b2sf = false;
	textObject.m_b3sf = true;
	
	textObject.Write(&fakeWriter);
	assertTest(fakeWriter.m_csBuf == "\\hich\\af37\\loch\\af27\\dbch\\f17");
}
示例#14
0
//TODO: load the tags still missing
const QString Filterkpr2odf::createGraphicStyle(const KXmlElement& element)
{
    //A graphic style is wiely used by a broad type of objects, hence can have many different properties
    KOdfGenericStyle style(KOdfGenericStyle::GraphicAutoStyle, "graphic");
    KXmlElement textObject(element.namedItem("TEXTOBJ").toElement());
    if (!textObject.isNull()) {
        if (textObject.hasAttribute("verticalAlign")) {
            QString textAligment = textObject.attribute("verticalAlign");
            if (textAligment == "center") {
                //all the other values are valid except center that is called middle in ODF
                textAligment = "middle";
            }
            style.addProperty("draw:textarea-vertical-align", textAligment);
        }
        if (textObject.hasAttribute("bleftpt")) {
            style.addPropertyPt("fo:padding-left", textObject.attribute("bleftpt").toDouble());
        }
        if (textObject.hasAttribute("bbottompt")) {
            style.addPropertyPt("fo:padding-bottom", textObject.attribute("bbottompt").toDouble());
        }
        if (textObject.hasAttribute("btoppt")) {
            style.addPropertyPt("fo:padding-top", textObject.attribute("btoppt").toDouble());
        }
        if (textObject.hasAttribute("brightpt")) {
            style.addPropertyPt("fo:padding-right", textObject.attribute("brightpt").toDouble());
        }
    }

    KXmlElement pen = element.namedItem("PEN").toElement();
    if (!pen.isNull()) {
        style.addPropertyPt("svg:stroke-width", pen.attribute("width").toDouble());
        style.addProperty("svg:stroke-color", pen.attribute("color"));

        QString stroke;
        int strokeStyle = pen.attribute("style").toInt();
        if (strokeStyle == 1) {
            stroke = "solid";
        } else if (strokeStyle >= 2 && strokeStyle <= 5) {
            stroke = "dash";
            style.addProperty("draw:stroke-dash", createStrokeDashStyle(strokeStyle));
        } else {
            stroke = "none";
        }
        style.addProperty("draw:stroke", stroke);
    } else {
        //even if the pen is not pressent for some objects it has to have a black stroke
        if (element.attribute("type") == "1"
                || element.attribute("type") == "2"
                || element.attribute("type") == "3"
                || element.attribute("type") == "5"
                || element.attribute("type") == "8"
                || element.attribute("type") == "11"
                || element.attribute("type") == "12"
                || element.attribute("type") == "13"
                || element.attribute("type") == "14"
                || element.attribute("type") == "15"
                || element.attribute("type") == "16") {
            style.addProperty("draw:stroke", "solid");
            style.addProperty("svg:stroke-width", "1px");
            style.addProperty("svg:stroke-color", "#000000");
        }
    }

    //We now define what's the object filled with, we "default" to a brush if both attributes are present
    KXmlElement brush = element.namedItem("BRUSH").toElement();
    KXmlElement fillType = element.namedItem("FILLTYPE").toElement();

    int fillTypeValue = 0;
    if (! fillType.isNull()) {
        fillTypeValue = fillType.attribute("value").toInt();
    }

    KXmlElement gradient = element.namedItem("GRADIENT").toElement();
    KXmlElement filename = element.namedItem("FILENAME").toElement();
    bool isConnection = filename.attribute("value").startsWith("Connections");
    QString fill;
    if (!brush.isNull() && !isConnection && fillTypeValue == 0) {
        QString fillColor(brush.attribute("color"));

        int brushStyle = brush.attribute("style").toInt();
        if (brushStyle == 1) {
            fill = "solid";
            style.addProperty("draw:fill-color", fillColor);
        } else if (brushStyle >= 9 && brushStyle <= 14) {
            fill = "hatch";
            style.addProperty("draw:fill-hatch-name",  createHatchStyle(brushStyle, fillColor));
        } else if (brushStyle >= 2 && brushStyle <= 8) {
            //in KPR files transparency was used in ODF opacity is used instead calculated as 100-transparency
            int opacity = 100;
            if (brushStyle == 2)
                opacity = 6;
            else if (brushStyle == 3)
                opacity = 12;
            else if (brushStyle == 4)
                opacity = 37;
            else if (brushStyle == 5)
                opacity = 50;
            else if (brushStyle == 6)
                opacity = 63;
            else if (brushStyle == 7)
                opacity = 88;
            else if (brushStyle == 8)
                opacity = 94;
            //Opacity is a gradient, in this case an uniform one
            style.addProperty("draw:opacity", createOpacityGradientStyle(opacity));
        }
    } else if (!gradient.isNull() && fillTypeValue == 1) {
        fill = "gradient";
        style.addProperty("draw:fill-gradient-name", createGradientStyle(gradient));
    } else {
        fill = "none";
    }

    if (!fill.isNull()) { //don't save ""
        style.addProperty("draw:fill", fill);
    }

    KXmlElement lineBegin = element.namedItem("LINEBEGIN").toElement();
    if (!lineBegin.isNull()) {
        style.addProperty("draw:marker-start-width", "0.25cm");

        int markerStyle = lineBegin.attribute("value").toInt();
        style.addProperty("draw:marker-start", createMarkerStyle(markerStyle));
    }

    KXmlElement lineEnd = element.namedItem("LINEEND").toElement();
    if (!lineEnd.isNull()) {
        style.addProperty("draw:marker-end-width", "0.25cm");

        int markerStyle = lineEnd.attribute("value").toInt();
        style.addProperty("draw:marker-end", createMarkerStyle(markerStyle));
    }

    KXmlElement shadow = element.namedItem("SHADOW").toElement();
    if (!shadow.isNull()) {
        style.addProperty("draw:shadow", "visible");
        style.addProperty("draw:shadow-color", shadow.attribute("color"));

        QString shadowOffsetX;
        QString shadowOffsetY;
        int direction = shadow.attribute("direction").toInt();
        QString distance = QString("%1pt").arg(shadow.attribute("distance").toDouble());
        //Enum: ShadowDirection
        switch (direction) {
        case 1: //Left Up
            shadowOffsetX = '-' + distance;
            shadowOffsetY = '-' + distance;
            break;
        case 2: //Up
            shadowOffsetX = "0pt";
            shadowOffsetY = '-' + distance;
            break;
        case 3: //Right Up
            shadowOffsetX = distance;
            shadowOffsetY = '-' + distance;
            break;
        case 4: //Right
            shadowOffsetX = distance;
            shadowOffsetY = "0pt";
            break;
        case 5: //Right Bottom
            shadowOffsetX = distance;
            shadowOffsetY = distance;
            break;
        case 6: //Bottom
            shadowOffsetX = "0pt";
            shadowOffsetY = distance;
            break;
        case 7: //Left Bottom
            shadowOffsetX = '-' + distance;
            shadowOffsetY = distance;
            break;
        case 8: //Left
            shadowOffsetX = '-' + distance;
            shadowOffsetY = "0pt";
            break;
        }
        style.addProperty("draw:shadow-offset-x", shadowOffsetX);
        style.addProperty("draw:shadow-offset-y", shadowOffsetY);
    }

    //If what we're loading is the style for an image and some form of mirror, luminance, greyscale... is applied to it we must load it in the GrpahicStyle
    KXmlElement pictureSettings = element.namedItem("PICTURESETTINGS").toElement();
    if (!pictureSettings.isNull()) {
        int mirrorType = pictureSettings.attribute("mirrorType", "0").toInt();
        QString mirror;
        switch (mirrorType) {
        case 0: //normal
            break;
        case 1:
            mirror = "horizontal";
            break;
        case 2:
            mirror = "vertical";
            break;
        case 3:
            mirror = "vertical horizontal";
            break;
        }
        if (!mirror.isNull()) {
            style.addProperty("style:mirror", mirror);
        }

        bool grayscal = pictureSettings.attribute("grayscal", "0") == "1";
        if (grayscal) {
            style.addProperty("draw:color-mode", "greyscale");
        }

        int bright = pictureSettings.attribute("bright", "0").toInt();
        if (bright != 0) {
            style.addProperty("draw:luminance", QString("%1%").arg(bright));
        }

        bool swapRGB = pictureSettings.attribute("bright", "0") == "1";
        if (swapRGB) {
            style.addProperty("draw:color-inversion", "true");
        }

        //NOTE: depth is not portable
    }

//     style.addAttribute( "style:parent-style-name", "standard" ); TODO: add the standard Graphic style
    style.setAutoStyleInStylesDotXml(m_sticky);

    return m_styles.insert(style, "gr");
}
示例#15
0
int InlineTextBox::positionForOffset(int offset) const
{
    ASSERT(offset >= m_start);
    ASSERT(offset <= m_start + m_len);

    if (isLineBreak())
        return m_x;

    RenderText* text = static_cast<RenderText*>(m_object);
    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, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride),
                                                   IntPoint(m_x, 0), 0, from, to)).right();
}
示例#16
0
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);
}
示例#17
0
void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, int deco, ShadowData* shadow)
{
    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, textPos(), m_firstLine);
    
    // Get the text decoration colors.
    Color underline, overline, linethrough;
    object()->getTextDecorationColors(deco, underline, overline, linethrough, true);
    
    // Use a special function for underlines to get the positioning exactly right.
    bool isPrinting = textObject()->document()->printing();
    context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.

    bool linesAreOpaque = !isPrinting && (!(deco & UNDERLINE) || underline.alpha() == 255) && (!(deco & OVERLINE) || overline.alpha() == 255) && (!(deco & LINE_THROUGH) || linethrough.alpha() == 255);

    bool setClip = false;
    int extraOffset = 0;
    if (!linesAreOpaque && shadow && shadow->next) {
        context->save();
        IntRect clipRect(tx, ty, width, m_baseline + 2);
        for (ShadowData* s = shadow; s; s = s->next) {
            IntRect shadowRect(tx, ty, width, m_baseline + 2);
            shadowRect.inflate(s->blur);
            shadowRect.move(s->x, s->y);
            clipRect.unite(shadowRect);
            extraOffset = max(extraOffset, max(0, s->y) + s->blur);
        }
        context->save();
        context->clip(clipRect);
        extraOffset += m_baseline + 2;
        ty += extraOffset;
        setClip = true;
    }

    bool setShadow = false;
    do {
        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);
            // Leave one pixel of white between the baseline and the underline.
            context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), width, isPrinting);
        }
        if (deco & OVERLINE) {
            context->setStrokeColor(overline);
            context->drawLineForText(IntPoint(tx, ty), width, isPrinting);
        }
        if (deco & LINE_THROUGH) {
            context->setStrokeColor(linethrough);
            context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), width, isPrinting);
        }
    } while (shadow);

    if (setClip)
        context->restore();
    else if (setShadow)
        context->clearShadow();
}
示例#18
0
void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
{
    if (isLineBreak() || !object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE ||
        m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline)
        return;
    
    ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);

    int xPos = tx + m_x - parent()->maxHorizontalVisualOverflow();
    int w = width() + 2 * parent()->maxHorizontalVisualOverflow();
    if (xPos >= paintInfo.rect.right() || xPos + w <= paintInfo.rect.x())
        return;

    bool isPrinting = textObject()->document()->printing();
    
    // Determine whether or not we're selected.
    bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone;
    if (!haveSelection && paintInfo.phase == PaintPhaseSelection)
        // When only painting the selection, don't bother to paint if there is none.
        return;

    GraphicsContext* context = paintInfo.context;

    // Determine whether or not we have composition underlines to draw.
    bool containsComposition = object()->document()->frame()->editor()->compositionNode() == object()->node();
    bool useCustomUnderlines = containsComposition && object()->document()->frame()->editor()->compositionUsesCustomUnderlines();

    // Set our font.
    RenderStyle* styleToUse = object()->style(m_firstLine);
    int d = styleToUse->textDecorationsInEffect();
    const Font* font = &styleToUse->font();
    if (*font != context->font())
        context->setFont(*font);

    // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
    // and composition underlines.
    if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) {
#if PLATFORM(MAC)
        // Custom highlighters go behind everything else.
        if (styleToUse->highlight() != nullAtom && !context->paintingDisabled())
            paintCustomHighlight(tx, ty, styleToUse->highlight());
#endif

        if (containsComposition && !useCustomUnderlines)
            paintCompositionBackground(context, tx, ty, styleToUse, font,
                object()->document()->frame()->editor()->compositionStart(),
                object()->document()->frame()->editor()->compositionEnd());

        paintDocumentMarkers(context, tx, ty, styleToUse, font, true);

        if (haveSelection && !useCustomUnderlines)
            paintSelection(context, tx, ty, styleToUse, font);
    }

    // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
    if (m_len <= 0)
        return;

    Color textFillColor;
    Color textStrokeColor;
    float textStrokeWidth = styleToUse->textStrokeWidth();
    ShadowData* textShadow = paintInfo.forceBlackText ? 0 : styleToUse->textShadow();

    if (paintInfo.forceBlackText) {
        textFillColor = Color::black;
        textStrokeColor = Color::black;
    } else {
        textFillColor = styleToUse->textFillColor();
        if (!textFillColor.isValid())
            textFillColor = styleToUse->color();

        // Make the text fill color legible against a white background
        if (styleToUse->forceBackgroundsToWhite())
            textFillColor = correctedTextColor(textFillColor, Color::white);

        textStrokeColor = styleToUse->textStrokeColor();
        if (!textStrokeColor.isValid())
            textStrokeColor = styleToUse->color();

        // Make the text stroke color legible against a white background
        if (styleToUse->forceBackgroundsToWhite())
            textStrokeColor = correctedTextColor(textStrokeColor, Color::white);
    }

    bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection);
    bool paintSelectedTextSeparately = false;

    Color selectionFillColor = textFillColor;
    Color selectionStrokeColor = textStrokeColor;
    float selectionStrokeWidth = textStrokeWidth;
    ShadowData* selectionShadow = textShadow;
    if (haveSelection) {
        // Check foreground color first.
        Color foreground = paintInfo.forceBlackText ? Color::black : object()->selectionForegroundColor();
        if (foreground.isValid() && foreground != selectionFillColor) {
            if (!paintSelectedTextOnly)
                paintSelectedTextSeparately = true;
            selectionFillColor = foreground;
        }

        if (RenderStyle* pseudoStyle = object()->getCachedPseudoStyle(RenderStyle::SELECTION)) {
            ShadowData* shadow = paintInfo.forceBlackText ? 0 : pseudoStyle->textShadow();
            if (shadow != selectionShadow) {
                if (!paintSelectedTextOnly)
                    paintSelectedTextSeparately = true;
                selectionShadow = shadow;
            }

            float strokeWidth = pseudoStyle->textStrokeWidth();
            if (strokeWidth != selectionStrokeWidth) {
                if (!paintSelectedTextOnly)
                    paintSelectedTextSeparately = true;
                selectionStrokeWidth = strokeWidth;
            }

            Color stroke = paintInfo.forceBlackText ? Color::black : pseudoStyle->textStrokeColor();
            if (!stroke.isValid())
                stroke = pseudoStyle->color();
            if (stroke != selectionStrokeColor) {
                if (!paintSelectedTextOnly)
                    paintSelectedTextSeparately = true;
                selectionStrokeColor = stroke;
            }
        }
    }

    IntPoint textOrigin(m_x + tx, m_y + ty + m_baseline);
    TextRun textRun(textObject()->text()->characters() + m_start, m_len, textObject()->allowTabs(), textPos(), m_toAdd, direction() == RTL, m_dirOverride || styleToUse->visuallyOrdered());

    int sPos = 0;
    int ePos = 0;
    if (paintSelectedTextOnly || paintSelectedTextSeparately)
        selectionStartEnd(sPos, ePos);

    if (!paintSelectedTextOnly) {
        // For stroked painting, we have to change the text drawing mode.  It's probably dangerous to leave that mutated as a side
        // effect, so only when we know we're stroking, do a save/restore.
        if (textStrokeWidth > 0)
            context->save();

        updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth);
        if (!paintSelectedTextSeparately || ePos <= sPos) {
            // FIXME: Truncate right-to-left text correctly.
            paintTextWithShadows(context, textRun, 0, m_truncation == cNoTruncation ? m_len : m_truncation, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);
        } else
            paintTextWithShadows(context, textRun, ePos, sPos, textOrigin, m_x + tx, m_y + ty, width(), height(), textShadow, textStrokeWidth > 0);

        if (textStrokeWidth > 0)
            context->restore();
    }

    if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) {
        // paint only the text that is selected
        if (selectionStrokeWidth > 0)
            context->save();

        updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth);
        paintTextWithShadows(context, textRun, sPos, ePos, textOrigin, m_x + tx, m_y + ty, width(), height(), selectionShadow, selectionStrokeWidth > 0);

        if (selectionStrokeWidth > 0)
            context->restore();
    }

    // Paint decorations
    if (d != TDNONE && paintInfo.phase != PaintPhaseSelection && styleToUse->htmlHacks()) {
        context->setStrokeColor(styleToUse->color());
        paintDecoration(context, tx, ty, d, textShadow);
    }

    if (paintInfo.phase == PaintPhaseForeground) {
        paintDocumentMarkers(context, tx, ty, styleToUse, font, false);

        if (useCustomUnderlines) {
            const Vector<CompositionUnderline>& underlines = object()->document()->frame()->editor()->customCompositionUnderlines();
            size_t numUnderlines = underlines.size();

            for (size_t index = 0; index < numUnderlines; ++index) {
                const CompositionUnderline& underline = underlines[index];

                if (underline.endOffset <= start())
                    // underline is completely before this run.  This might be an underline that 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.
                    paintCompositionUnderline(context, 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;
            }
        }
    }
}
示例#19
0
bool InlineTextBox::isLineBreak() const
{
    return object()->isBR() || (object()->style()->preserveNewline() && len() == 1 && (*textObject()->text())[start()] == '\n');
}