void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
{
    FS_STATE* iType = font->platformData().scaledFont(context->getCTM().yScale());
    if (!iType)
        return;

    FloatPoint adjustedPoint = point;

    if (font->platformData().orientation() == Vertical)
        adjustedPoint.move(-(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent()), 0);

    bool softwareBlurRequired = context->state().shadowBlur / font->fontMetrics().xHeight() > 0.5;

    FloatSize currentShadowOffset;
    float currentShadowBlur;
    Color currentShadowColor;
    ColorSpace currentColorSpace;

    // If we have a shadow blur, and it is too big to apply at text-render time, we must render it now.
    if (context->hasShadow() && softwareBlurRequired) {
        context->getShadow(currentShadowOffset, currentShadowBlur, currentShadowColor, currentColorSpace);

        const GraphicsContextState state = context->state();
        FloatSize offset = state.shadowOffset;
        if (state.shadowsIgnoreTransforms)
            offset.setHeight(-offset.height());
        ShadowBlur shadow(FloatSize(state.shadowBlur, state.shadowBlur), offset, state.shadowColor, state.shadowColorSpace);
        FloatPoint minPoint(adjustedPoint.x(), adjustedPoint.y() - fontMetrics().ascent());
        FloatPoint maxPoint(adjustedPoint.x(), adjustedPoint.y() + fontMetrics().descent());
        FloatPoint currentPoint = adjustedPoint;
        for (int i = 0; i < numGlyphs; ++i) {
            currentPoint += *glyphBuffer.advances(from + i);
            minPoint.setX(std::min(minPoint.x(), currentPoint.x()));
            minPoint.setY(std::min(minPoint.y(), currentPoint.y()));
            maxPoint = maxPoint.expandedTo(currentPoint);
        }
        const FloatRect boundingRect(minPoint.x(), minPoint.y(), maxPoint.x() - minPoint.x(), maxPoint.y() - minPoint.y());
        GraphicsContext* shadowContext = shadow.beginShadowLayer(context, boundingRect);
        if (shadowContext) {
            iType = font->platformData().scaledFont(shadowContext->getCTM().yScale());
            shadowContext->platformContext()->addGlyphs(glyphBuffer.glyphs(from),
                    reinterpret_cast<const BlackBerry::Platform::FloatSize*>(glyphBuffer.advances(from)),
                    numGlyphs, adjustedPoint, iType, 0, 0);
            iType = font->platformData().scaledFont(context->getCTM().yScale());
            shadow.endShadowLayer(context);
        }
        context->platformContext()->clearShadow();
    }

    context->platformContext()->addGlyphs(glyphBuffer.glyphs(from),
                                          reinterpret_cast<const BlackBerry::Platform::FloatSize*>(glyphBuffer.advances(from)),
                                          numGlyphs, adjustedPoint, iType,
                                          context->fillGradient() ? context->fillGradient()->platformGradient() : (context->fillPattern() ? context->fillPattern()->platformPattern(AffineTransform()) : static_cast<BlackBerry::Platform::Graphics::Paint*>(0)),
                                          context->strokeGradient() ? context->strokeGradient()->platformGradient() : (context->strokePattern() ? context->strokePattern()->platformPattern(AffineTransform()) : static_cast<BlackBerry::Platform::Graphics::Paint*>(0)));

    if (softwareBlurRequired)
        context->platformContext()->setShadow(currentShadowOffset, currentShadowBlur, currentShadowColor.isValid() ? currentShadowColor.rgb() : makeRGBA(0, 0, 0, 0xFF / 3), context->state().shadowsIgnoreTransforms);
}
Exemple #2
0
void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer, 
                      int from, int numGlyphs, const FloatPoint& point) const
{
    CGContextRef cgContext = graphicsContext->platformContext();

    uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext);

    const FontPlatformData& platformData = font->platformData();
    //NSFont* drawFont;
    //if ([gContext isDrawingToScreen]) {
    //    drawFont = [platformData.font screenFont];
    //    if (drawFont != platformData.font)
    //        // We are getting this in too many places (3406411); use ERROR so it only prints on debug versions for now. (We should debug this also, eventually).
    //        LOG_ERROR("Attempting to set non-screen font (%@) when drawing to screen.  Using screen font anyway, may result in incorrect metrics.",
    //            [[[platformData.font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
    //} else {
    //    drawFont = [platformData.font printerFont];
    //    if (drawFont != platformData.font)
    //        NSLog(@"Attempting to set non-printer font (%@) when printing.  Using printer font anyway, may result in incorrect metrics.",
    //            [[[platformData.font fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
    //}

    CGContextSetFont(cgContext, platformData.cgFont());

    CGAffineTransform matrix = CGAffineTransformIdentity;
    matrix.b = -matrix.b;
    matrix.d = -matrix.d;

    if (platformData.syntheticOblique())
    {
        static float skew = -tanf(syntheticObliqueAngle * acosf(0) / 90);
        matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0));
    }

    // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
    FloatSize translation = glyphBuffer.offsetAt(from);
    if (translation.width() || translation.height())
        CGAffineTransformTranslate(matrix, translation.width(), translation.height());
    
    CGContextSetTextMatrix(cgContext, matrix);

    //wkSetCGFontRenderingMode(cgContext, drawFont);
    CGContextSetFontSize(cgContext, platformData.size());
    CGContextSetTextPosition(cgContext, point.x(), point.y());
    CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    if (font->m_syntheticBoldOffset) {
        CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y());
        CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    }

    wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
}
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
{
#if USE(WXGC)
    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
#else
    wxDC* dc = graphicsContext->platformContext();
#endif

    wxFont wxfont = font->getWxFont();
    if (wxfont.IsOk())
        dc->SetFont(wxfont);
    dc->SetTextForeground(color);

    // convert glyphs to wxString
    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
    int offset = point.x();
    wxString text = wxEmptyString;
    for (unsigned i = 0; i < numGlyphs; i++) {
        text = text.Append((wxChar)glyphs[i]);
        offset += glyphBuffer.advanceAt(from + i);
    }
    
    // the y point is actually the bottom point of the text, turn it into the top
    float height = font->ascent() - font->descent();
    wxCoord ypoint = (wxCoord) (point.y() - height);
     
    dc->DrawText(text, (wxCoord)point.x(), ypoint);
}
Exemple #4
0
void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    cairo_t* context = graphicsContext->platformContext();

    // Set the text color to use for drawing.
    float red, green, blue, alpha;
    Color penColor = graphicsContext->fillColor();
    penColor.getRGBA(red, green, blue, alpha);
    cairo_set_source_rgba(context, red, green, blue, alpha);

    // This was commented out as it made "some text invisible" but seems to work now.
    font->setFont(context);

    GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*) glyphBuffer.glyphs(from);

    float offset = point.x();

    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = point.y();
        offset += glyphBuffer.advanceAt(from + i);
    }
    cairo_show_glyphs(context, glyphs, numGlyphs);
}
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
{
#if USE(WXGC)
    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
#else
    wxDC* dc = graphicsContext->platformContext();
#endif

    wxFont* wxfont = font->getWxFont();
    if (wxfont->IsOk())
        dc->SetFont(*wxfont);
    dc->SetTextForeground(color);

    // convert glyphs to wxString
    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
    int offset = point.x();
    wxString text = wxEmptyString;
    for (unsigned i = 0; i < numGlyphs; i++) {
        text = text.Append((wxChar)glyphs[i]);
        offset += glyphBuffer.advanceAt(from + i);
    }
    
    // NOTE: The wx API actually adds the ascent to the y value internally,
    // so we have to subtract it from the y point here so that the ascent
    // isn't added twice. 
    dc->DrawText(text, (wxCoord)point.x(), int(point.y() - font->ascent()));
}
Exemple #6
0
void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    cairo_t* context = graphicsContext->platformContext();

    // Set the text color to use for drawing.
    float red, green, blue, alpha;
    Color penColor = graphicsContext->pen().color();
    penColor.getRGBA(red, green, blue, alpha);
    cairo_set_source_rgba(context, red, green, blue, alpha);

    // Select the scaled font.
    font->setFont(context);

    GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);

    float offset = point.x();

    for (unsigned i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = point.y();
        offset += glyphBuffer.advanceAt(from + i);
    }
    cairo_show_glyphs(context, glyphs, numGlyphs);
}
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
{
    graphicsContext->save();
    
    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());

    wxFont* wxfont = font->getWxFont();
    graphicsContext->setFillColor(graphicsContext->fillColor(), ColorSpaceDeviceRGB);

    CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext());

    CGFontRef cgFont = font->platformData().cgFont();
    
    CGContextSetFont(cgContext, cgFont);

    CGContextSetFontSize(cgContext, wxfont->GetPointSize());

    CGFloat red, green, blue, alpha;
    graphicsContext->fillColor().getRGBA(red, green, blue, alpha);
    CGContextSetRGBFillColor(cgContext, red, green, blue, alpha);

    CGAffineTransform matrix = CGAffineTransformIdentity;
    matrix.b = -matrix.b;
    matrix.d = -matrix.d;
    
    CGContextSetTextMatrix(cgContext, matrix);

    CGContextSetTextPosition(cgContext, point.x(), point.y());
    
    CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    
    if (cgFont)
        CGFontRelease(cgFont);
    graphicsContext->restore();
}
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
{
#if USE(WXGC)
    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
#else
    wxDC* dc = graphicsContext->platformContext();
#endif

    // get the native HDC handle to draw using native APIs
    HDC hdc = 0;
#if USE(WXGC)
    wxGraphicsContext* gc = dc->GetGraphicsContext();
    Gdiplus::Graphics* g;
    if (gc) {
        g = (Gdiplus::Graphics*)gc->GetNativeContext();
        hdc = g->GetHDC();
    }
#else
    hdc = static_cast<HDC>(dc->GetHDC());
#endif

    // ExtTextOut wants the offsets as an array of ints, so extract them
    // from the glyph buffer
    const GlyphBufferGlyph*   glyphs   = glyphBuffer.glyphs(from);
    const GlyphBufferAdvance* advances = glyphBuffer.advances(from);

    float y = point.y() - font->ascent();
    float x = point.x();

    int* spacing = new int[numGlyphs - from];
    for (unsigned i = 0; i < numGlyphs; ++i)
        spacing[i] = advances[i].width();

    wxFont* wxfont = font->getWxFont();
    if (wxfont && wxfont->IsOk())
        ::SelectObject(hdc, GetHfontOf(*wxfont));

    if (color.Ok())
        ::SetTextColor(hdc, color.GetPixel());

    // do not draw background behind characters
    ::SetBkMode(hdc, TRANSPARENT);

    // draw text with optional character widths array
    wxString string = wxString((wxChar*)(&glyphs[from]), numGlyphs);
    ::ExtTextOut(hdc, x, y, 0, NULL, string.c_str(), string.length(), spacing);

    ::SetBkMode(hdc, TRANSPARENT);

    #if USE(WXGC)
        g->ReleaseHDC(hdc);
    #endif

    delete [] spacing;
}
Exemple #9
0
    void TraceGlyphBufferToString(const SimpleFontData* pSimpleFontData, const GlyphBuffer& glyphBuffer, int glyphIndexBegin, int glyphCount, const FloatPoint& point)
    {
        eastl::fixed_string<char8_t, 128> sDebug;
        sDebug.sprintf("[%d,%d] ", (int)point.x(), (int)point.y());

        GlyphBufferGlyph* pGlyphArray = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(glyphIndexBegin));

        for(int i = glyphIndexBegin; i < glyphIndexBegin + glyphCount; ++i, ++pGlyphArray)
            sDebug += (char8_t)ConvertGlyphToChar(pSimpleFontData->m_font.mpFont, *pGlyphArray);

        sDebug += "\n";

       OWB_PRINTF("%s", sDebug.c_str());
    }
Exemple #10
0
void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    QPainter& p = *graphicsContext->platformContext();

    Color color = graphicsContext->fillColor();
    p.setPen(QColor(color));
    p.setFont(font->platformData().font());

    const QChar* buffer = reinterpret_cast<const QChar*>(glyphBuffer.glyphs(from));
    QString str = QString::fromRawData(buffer, numGlyphs);

    p.drawText(point, str);
}
Exemple #11
0
TEST(GlyphBufferTest, GlyphArrayWithOffset) {
  RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
  RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();

  GlyphBuffer glyphBuffer;
  glyphBuffer.add(42, font1.get(), 10);
  glyphBuffer.add(43, font1.get(), 15);
  glyphBuffer.add(44, font2.get(), 12);

  EXPECT_FALSE(glyphBuffer.isEmpty());
  EXPECT_EQ(3u, glyphBuffer.size());

  const Glyph* glyphs = glyphBuffer.glyphs(1);
  EXPECT_EQ(43, glyphs[0]);
  EXPECT_EQ(44, glyphs[1]);
}
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    if (!font->platformData().size())
        return;

    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));

    float offset = point.x();
    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = point.y();
        offset += glyphBuffer.advanceAt(from + i).width();
    }

    PlatformContextCairo* platformContext = context->platformContext();
    drawGlyphsShadow(context, point, font, glyphs, numGlyphs);

    cairo_t* cr = platformContext->cr();
    cairo_save(cr);

    if (context->textDrawingMode() & TextModeFill) {
        platformContext->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha);
        drawGlyphsToContext(cr, font, glyphs, numGlyphs);
    }

    // Prevent running into a long computation within cairo. If the stroke width is
    // twice the size of the width of the text we will not ask cairo to stroke
    // the text as even one single stroke would cover the full wdth of the text.
    //  See https://bugs.webkit.org/show_bug.cgi?id=33759.
    if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) {
        platformContext->prepareForStroking(context->state());
        cairo_set_line_width(cr, context->strokeThickness());

        // This may disturb the CTM, but we are going to call cairo_restore soon after.
        cairo_set_scaled_font(cr, font->platformData().scaledFont());
        cairo_glyph_path(cr, glyphs, numGlyphs);
        cairo_stroke(cr);
    }

    cairo_restore(cr);
}
Exemple #13
0
TEST(GlyphBufferTest, StoresGlyphs) {
  RefPtr<SimpleFontData> font1 = TestSimpleFontData::create();
  RefPtr<SimpleFontData> font2 = TestSimpleFontData::create();

  GlyphBuffer glyphBuffer;
  glyphBuffer.add(42, font1.get(), 10);
  glyphBuffer.add(43, font1.get(), 15);
  glyphBuffer.add(44, font2.get(), 22);

  EXPECT_FALSE(glyphBuffer.isEmpty());
  EXPECT_FALSE(glyphBuffer.hasVerticalOffsets());
  EXPECT_EQ(3u, glyphBuffer.size());

  EXPECT_EQ(42, glyphBuffer.glyphAt(0));
  EXPECT_EQ(43, glyphBuffer.glyphAt(1));
  EXPECT_EQ(44, glyphBuffer.glyphAt(2));

  const Glyph* glyphs = glyphBuffer.glyphs(0);
  EXPECT_EQ(42, glyphs[0]);
  EXPECT_EQ(43, glyphs[1]);
  EXPECT_EQ(44, glyphs[2]);
}
Exemple #14
0
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    CGContextRef cgContext = graphicsContext->platformContext();
    bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();

    switch(fontDescription().fontSmoothing()) {
    case Antialiased: {
        graphicsContext->setShouldAntialias(true);
        shouldUseFontSmoothing = false;
        break;
    }
    case SubpixelAntialiased: {
        graphicsContext->setShouldAntialias(true);
        shouldUseFontSmoothing = true;
        break;
    }
    case NoSmoothing: {
        graphicsContext->setShouldAntialias(false);
        shouldUseFontSmoothing = false;
        break;
    }
    case AutoSmoothing: {
        // For the AutoSmooth case, don't do anything! Keep the default settings.
        break;
    }
    default:
        ASSERT_NOT_REACHED();
    }

    if (font->platformData().useGDI() && !shouldUseFontSmoothing) {
        drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
        return;
    }

    uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing);

    const FontPlatformData& platformData = font->platformData();

    CGContextSetFont(cgContext, platformData.cgFont());

    CGAffineTransform matrix = CGAffineTransformIdentity;
    matrix.b = -matrix.b;
    matrix.d = -matrix.d;

    if (platformData.syntheticOblique()) {
        static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f);
        matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0));
    }

    CGContextSetTextMatrix(cgContext, matrix);

    // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
    FloatSize translation = glyphBuffer.offsetAt(from);

    CGContextSetFontSize(cgContext, platformData.size());
    wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI());

    FloatSize shadowOffset;
    float shadowBlur;
    Color shadowColor;
    ColorSpace shadowColorSpace;
    graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);

    bool hasSimpleShadow = graphicsContext->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext->shadowsIgnoreTransforms() || graphicsContext->getCTM().isIdentityOrTranslationOrFlipped());
    if (hasSimpleShadow) {
        // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
        graphicsContext->clearShadow();
        Color fillColor = graphicsContext->fillColor();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB);
        float shadowTextX = point.x() + translation.width() + shadowOffset.width();
        // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative.
        float shadowTextY = point.y() + translation.height() + shadowOffset.height() * (graphicsContext->shadowsIgnoreTransforms() ? -1 : 1);
        CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY);
        CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
        if (font->syntheticBoldOffset()) {
            CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height());
            CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
        }
        graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB);
    }

    CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
    CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    if (font->syntheticBoldOffset()) {
        CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height());
        CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    }

    if (hasSimpleShadow)
        graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB);

    wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
}
Exemple #15
0
static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                          int from, int numGlyphs, const FloatPoint& point)
{
    Color fillColor = graphicsContext->fillColor();

    bool drawIntoBitmap = false;
    TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode();
    if (drawingMode == TextModeFill) {
        if (!fillColor.alpha())
            return;

        drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer();
        if (!drawIntoBitmap) {
            FloatSize offset;
            float blur;
            Color color;
            ColorSpace shadowColorSpace;

            graphicsContext->getShadow(offset, blur, color, shadowColorSpace);
            drawIntoBitmap = offset.width() || offset.height() || blur;
        }
    }

    // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances.
    Vector<int, 2048> gdiAdvances;
    int totalWidth = 0;
    for (int i = 0; i < numGlyphs; i++) {
        gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i)));
        totalWidth += gdiAdvances[i];
    }

    HDC hdc = 0;
    OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
    IntRect textRect;
    if (!drawIntoBitmap)
        hdc = graphicsContext->getWindowsContext(textRect, true, false);
    if (!hdc) {
        drawIntoBitmap = true;
        // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges.
        // FIXME: Can get glyphs' optical bounds (even from CG) to get this right.
        const FontMetrics& fontMetrics = font->fontMetrics();
        int lineGap = fontMetrics.lineGap();
        textRect = IntRect(point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2,
                           point.y() - fontMetrics.ascent() - lineGap,
                           totalWidth + fontMetrics.ascent() + fontMetrics.descent(),
                           fontMetrics.lineSpacing());
        bitmap = graphicsContext->createWindowsBitmap(textRect.size());
        memset(bitmap->buffer(), 255, bitmap->bufferLength());
        hdc = bitmap->hdc();

        XFORM xform;
        xform.eM11 = 1.0f;
        xform.eM12 = 0.0f;
        xform.eM21 = 0.0f;
        xform.eM22 = 1.0f;
        xform.eDx = -textRect.x();
        xform.eDy = -textRect.y();
        SetWorldTransform(hdc, &xform);
    }

    SelectObject(hdc, font->platformData().hfont());

    // Set the correct color.
    if (drawIntoBitmap)
        SetTextColor(hdc, RGB(0, 0, 0));
    else
        SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue()));

    SetBkMode(hdc, TRANSPARENT);
    SetTextAlign(hdc, TA_LEFT | TA_BASELINE);

    // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
    FloatSize translation = glyphBuffer.offsetAt(from);
    if (translation.width() || translation.height()) {
        XFORM xform;
        xform.eM11 = 1.0;
        xform.eM12 = 0;
        xform.eM21 = 0;
        xform.eM22 = 1.0;
        xform.eDx = translation.width();
        xform.eDy = translation.height();
        ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
    }

    if (drawingMode == TextModeFill) {
        XFORM xform;
        xform.eM11 = 1.0;
        xform.eM12 = 0;
        xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0;
        xform.eM22 = 1.0;
        xform.eDx = point.x();
        xform.eDy = point.y();
        ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
        ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
        if (font->syntheticBoldOffset()) {
            xform.eM21 = 0;
            xform.eDx = font->syntheticBoldOffset();
            xform.eDy = 0;
            ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
            ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
        }
    } else {
        XFORM xform;
        GetWorldTransform(hdc, &xform);
        AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy);
        CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity;
        if (font->platformData().syntheticOblique())
            initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0));
        initialGlyphTransform.tx = 0;
        initialGlyphTransform.ty = 0;
        CGContextRef cgContext = graphicsContext->platformContext();

        CGContextSaveGState(cgContext);

        BOOL fontSmoothingEnabled = false;
        SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
        CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled);

        CGContextScaleCTM(cgContext, 1.0, -1.0);
        CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height()));

        for (unsigned i = 0; i < numGlyphs; ++i) {
            RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
            CGContextSaveGState(cgContext);
            CGContextConcatCTM(cgContext, initialGlyphTransform);

            if (drawingMode & TextModeFill) {
                CGContextAddPath(cgContext, glyphPath.get());
                CGContextFillPath(cgContext);
                if (font->syntheticBoldOffset()) {
                    CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0);
                    CGContextAddPath(cgContext, glyphPath.get());
                    CGContextFillPath(cgContext);
                    CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0);
                }
            }
            if (drawingMode & TextModeStroke) {
                CGContextAddPath(cgContext, glyphPath.get());
                CGContextStrokePath(cgContext);
                if (font->syntheticBoldOffset()) {
                    CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0);
                    CGContextAddPath(cgContext, glyphPath.get());
                    CGContextStrokePath(cgContext);
                    CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0);
                }
            }

            CGContextRestoreGState(cgContext);
            CGContextTranslateCTM(cgContext, gdiAdvances[i], 0);
        }

        CGContextRestoreGState(cgContext);
    }

    if (drawIntoBitmap) {
        UInt8* buffer = bitmap->buffer();
        unsigned bufferLength = bitmap->bufferLength();
        for (unsigned i = 0; i < bufferLength; i += 4) {
            // Use green, which is always in the middle.
            UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255;
            buffer[i] = fillColor.blue();
            buffer[i + 1] = fillColor.green();
            buffer[i + 2] = fillColor.red();
            buffer[i + 3] = alpha;
        }
        graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.location());
    } else
        graphicsContext->releaseWindowsContext(hdc, textRect, true, false);
}
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
{
    graphicsContext->save();
    
    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());

    wxFont* wxfont = font->getWxFont();
    graphicsContext->setFillColor(graphicsContext->fillColor(), DeviceColorSpace);

    CGContextRef cgContext = static_cast<CGContextRef>(dc->GetGraphicsContext()->GetNativeContext());

    CGFontRef cgFont;

#ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT
    cgFont = CTFontCopyGraphicsFont((CTFontRef)wxfont->OSXGetCTFont(), NULL);
#else
    ATSFontRef fontRef;
    
    fontRef = FMGetATSFontRefFromFont(wxfont->MacGetATSUFontID());
    
    if (fontRef)
        cgFont = CGFontCreateWithPlatformFont((void*)&fontRef);
#endif
    
    CGContextSetFont(cgContext, cgFont);

    CGContextSetFontSize(cgContext, wxfont->GetPointSize());

    CGFloat red, green, blue, alpha;
    graphicsContext->fillColor().getRGBA(red, green, blue, alpha);
    CGContextSetRGBFillColor(cgContext, red, green, blue, alpha);

    CGAffineTransform matrix = CGAffineTransformIdentity;
    matrix.b = -matrix.b;
    matrix.d = -matrix.d;
    
    CGContextSetTextMatrix(cgContext, matrix);

    CGContextSetTextPosition(cgContext, point.x(), point.y());
    
    const FloatSize* advanceSizes = static_cast<const FloatSize*>(glyphBuffer.advances(from));
    int size = glyphBuffer.size() - from;
    CGSize sizes[size];
    CGGlyph glyphs[numGlyphs];
    
    // if the function doesn't exist, we're probably on tiger and need to grab the
    // function under its old name, CGFontGetGlyphsForUnicodes
    if (!CGFontGetGlyphsForUnichars)
        CGFontGetGlyphsForUnichars = (CGFontGetGlyphsForUnicharsPtr)dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes");
    
    // Let's make sure we got the function under one name or another!
    ASSERT(CGFontGetGlyphsForUnichars);
    CGFontGetGlyphsForUnichars(cgFont, glyphBuffer.glyphs(from), glyphs, numGlyphs);
    
    for (int i = 0; i < size; i++) {
        FloatSize fsize = advanceSizes[i];
        sizes[i] = CGSizeMake(fsize.width(), fsize.height());
    }
    
    CGContextShowGlyphsWithAdvances(cgContext, glyphs, sizes, numGlyphs);
    
    if (cgFont)
        CGFontRelease(cgFont);
    graphicsContext->restore();
}
Exemple #17
0
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    cairo_t* cr = context->platformContext();
    cairo_save(cr);

    font->setFont(cr);

    GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);

    float offset = point.x();
    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = point.y();
        offset += glyphBuffer.advanceAt(from + i);
    }

    Color fillColor = context->fillColor();

    // Text shadow, inspired by FontMac
    IntSize shadowSize;
    int shadowBlur = 0;
    Color shadowColor;
    bool hasShadow = context->textDrawingMode() == cTextFill &&
        context->getShadow(shadowSize, shadowBlur, shadowColor);

    // TODO: Blur support
    if (hasShadow) {
        // Disable graphics context shadows (not yet implemented) and paint them manually
        context->clearShadow();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        cairo_save(cr);

        float red, green, blue, alpha;
        shadowFillColor.getRGBA(red, green, blue, alpha);
        cairo_set_source_rgba(cr, red, green, blue, alpha);

        cairo_translate(cr, shadowSize.width(), shadowSize.height());
        cairo_show_glyphs(cr, glyphs, numGlyphs);

        cairo_restore(cr);
    }

    if (context->textDrawingMode() & cTextFill) {
        if (context->fillGradient()) {
            cairo_set_source(cr, context->fillGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->fillPattern()) {
            TransformationMatrix affine;
            cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine));
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else {
            float red, green, blue, alpha;
            fillColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        }
        cairo_show_glyphs(cr, glyphs, numGlyphs);
    }

    if (context->textDrawingMode() & cTextStroke) {
        if (context->strokeGradient()) {
            cairo_set_source(cr, context->strokeGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->strokePattern()) {
            TransformationMatrix affine;
            cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine));
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else {
            Color strokeColor = context->strokeColor();
            float red, green, blue, alpha;
            strokeColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        } 
        cairo_glyph_path(cr, glyphs, numGlyphs);
        cairo_set_line_width(cr, context->strokeThickness());
        cairo_stroke(cr);
    }

    // Re-enable the platform shadow we disabled earlier
    if (hasShadow)
        context->setShadow(shadowSize, shadowBlur, shadowColor);

    cairo_restore(cr);
}
Exemple #18
0
static void drawglyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point, float height, float ascent,
                      uint32 penalpha, uint32 penr, uint32 peng, uint32 penb, int shadowx, int shadowy)
{
    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
    struct OutlineFont *face = font->m_platformData.m_face;
    uint32 ysize = font->m_platformData.m_size;

    int32 imagewidth = 0;
    uint32 onlyspaces = TRUE;
    for (int i = 0; i < numGlyphs; i++) {
        if (32 != glyphs[i])
            onlyspaces = FALSE;
        imagewidth += glyphBuffer.advanceAt(from + i);
    }

    if (onlyspaces)
       return;

    if (imagewidth <= 0)
        return;

    imagewidth += 2 * (ysize * amigaConfig.fontXDPI / 72);

    Vector<unsigned> *glyphRGBABuffer = new Vector<unsigned>(imagewidth * height);
    if (!glyphRGBABuffer)
        return;

    glyphRGBABuffer->fill(0);

    int32 offsetinimg = 0;
    uint32 shiftleft = 0;

    for (int i = 0; i < numGlyphs; i++) {
        if (32 == glyphs[i]) {
            offsetinimg += glyphBuffer.advanceAt(from + i);
            continue;
        }

        struct GlyphMap *glyph;

        if (IDiskfont->ESetInfo(&face->olf_EEngine,
                                OT_GlyphCode, glyphs[i],
                                TAG_END))
            continue; //do not handle error

        struct OutlineFont *curface = face;
        if (IDiskfont->EObtainInfo(&face->olf_EEngine,
                                   OT_GlyphMap8Bit, &glyph,
                                   TAG_END)) {
            uint32 ok = FALSE;

            if (amigaConfig.unicodeFace
             && !IDiskfont->ESetInfo(&amigaConfig.unicodeFace->olf_EEngine,
                                     OT_PointHeight, ysize << 16,
                                     OT_GlyphCode, glyphs[i],
                                     TAG_END)
             && !IDiskfont->EObtainInfo(&amigaConfig.unicodeFace->olf_EEngine,
                                        OT_GlyphMap8Bit, &glyph,
                                        TAG_END)) {
                curface = amigaConfig.unicodeFace;
                ok = TRUE;
            }

            if (!ok
             && !IDiskfont->ESetInfo(&face->olf_EEngine,
                                     OT_GlyphCode, 0xFFFD,
                                     TAG_END)
             && !IDiskfont->EObtainInfo(&face->olf_EEngine,
                                        OT_GlyphMap8Bit, &glyph,
                                        TAG_END))
                ok = TRUE;

            if (!ok
             && !IDiskfont->ESetInfo(&face->olf_EEngine,
                                     OT_GlyphCode, '?',
                                     TAG_END)
             && !IDiskfont->EObtainInfo(&face->olf_EEngine,
                                        OT_GlyphMap8Bit, &glyph,
                                        TAG_END))
                ok = TRUE;

            if (!ok)
                continue; //do not handle error
        }

        if (amigaConfig.fontKerning && i > 0)
            if (!IDiskfont->ESetInfo(&curface->olf_EEngine,
                                     OT_GlyphCode, glyphs[i -1],
                                     OT_GlyphCode2, glyphs[i],
                                     TAG_END)) {
                FIXED kern = 0;
                if (!IDiskfont->EObtainInfo(&curface->olf_EEngine,
                                            OT_TextKernPair, &kern,
                                            TAG_END))
                    if (kern)
                        offsetinimg -= (int)(kern / 65536.0 * ysize * amigaConfig.fontYDPI / 72);
            }

        uint32 left = glyph->glm_BlackLeft;
        uint32 top = glyph->glm_BlackTop;
        int32 width = glyph->glm_BlackWidth;
        int32 gheight = glyph->glm_BlackHeight;
        int32 x0 = glyph->glm_X0;
        int32 y0 = glyph->glm_Y0;
        uint32 modulo = glyph->glm_BMModulo;
        int32 imgoffsetx = -x0 + left;

        if (offsetinimg + imgoffsetx < 0) {
            if (0 == i) {
                shiftleft = -imgoffsetx;
                if (shiftleft > ysize) {
                    shiftleft = ysize;
                    imgoffsetx = -ysize;
                }
                offsetinimg = shiftleft;
            }
            else
                imgoffsetx = 0;
        }

        int32 imgoffsety = ascent - y0 + top;

        if (imgoffsety < 0)
            imgoffsety = 0;

        if (offsetinimg + imgoffsetx + width > imagewidth) {
            int32 signedwidth = imagewidth - offsetinimg - imgoffsetx;
            if (signedwidth < 0)
                signedwidth = 0;
            width = signedwidth;
        }

        if (imgoffsety + gheight > (int)height)
            gheight = height - imgoffsety;

        for (int32 y = 0; y < gheight ; y++) {
            uint32 top_mod_left = (y + top) * modulo + left;
            for (int32 x = 0; x < width; x++)
                if ((offsetinimg + imgoffsetx + x < imagewidth)
                 && (offsetinimg + imgoffsetx + x >= 0)) {
                    uint32 a = penalpha * glyph->glm_BitMap[top_mod_left + x] / 255;
                    if (a) {
                        uint32 oldARGB = (*glyphRGBABuffer)[(imgoffsety + y) * imagewidth + offsetinimg + imgoffsetx + x];
                        if (oldARGB)
                            a = std::max((oldARGB >> 24), a);
                        (*glyphRGBABuffer)[(imgoffsety + y) * imagewidth + offsetinimg + imgoffsetx + x] = (a << 24) | ((penr * a / 255) << 16) | ((peng * a / 255) << 8) | (penb * a / 255);
                    }
                }
        }

        offsetinimg += glyphBuffer.advanceAt(from + i);

        IDiskfont->EReleaseInfo(&curface->olf_EEngine, OT_GlyphMap8Bit, glyph, TAG_END);
    }
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
                      const FloatPoint& point) const
{
    // compile-time assert
    SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t));

    SkPaint paint;
    if (!setupForText(&paint, gc, font)) {
        return;
    }
    
    SkScalar                    x = SkFloatToScalar(point.x());
    SkScalar                    y = SkFloatToScalar(point.y());
    const GlyphBufferGlyph*     glyphs = glyphBuffer.glyphs(from);
    const GlyphBufferAdvance*   adv = glyphBuffer.advances(from);
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
    SkPoint*                    pos = storage.get();
    
    SkCanvas* canvas = gc->platformContext()->mCanvas;

    /*  We need an array of [x,y,x,y,x,y,...], but webkit is giving us
        point.xy + [width, height, width, height, ...], so we have to convert
     */

    if (EmojiFont::IsAvailable()) {
        // set filtering, to make scaled images look nice(r)
        paint.setFilterBitmap(true);
        
        int localIndex = 0;
        int localCount = 0;
        for (int i = 0; i < numGlyphs; i++) {
            if (EmojiFont::IsEmojiGlyph(glyphs[i])) {
                if (localCount)
                    canvas->drawPosText(&glyphs[localIndex],
                                        localCount * sizeof(uint16_t),
                                        &pos[localIndex], paint);
                EmojiFont::Draw(canvas, glyphs[i], x, y, paint);
                // reset local index/count track for "real" glyphs
                localCount = 0;
                localIndex = i + 1;
            } else {
                pos[i].set(x, y);
                localCount += 1;
            }
            x += SkFloatToScalar(adv[i].width());
            y += SkFloatToScalar(adv[i].height());
        }
        // draw the last run of glyphs (if any)
        if (localCount)
            canvas->drawPosText(&glyphs[localIndex],
                                localCount * sizeof(uint16_t),
                                &pos[localIndex], paint);
    } else {
        for (int i = 0; i < numGlyphs; i++) {
            pos[i].set(x, y);
            x += SkFloatToScalar(adv[i].width());
            y += SkFloatToScalar(adv[i].height());
        }
        canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint);
    }
}
Exemple #20
0
void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
{
#if USE(WXGC)
    wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
    wxGraphicsContext* gc = dc->GetGraphicsContext();
    gc->PushState();
    cairo_t* cr = (cairo_t*)gc->GetNativeContext();

    wxFont* wxfont = font->getWxFont();
    cairo_scaled_font_t* scaled_font = 0;
#if wxUSE_PANGO
    PangoFont* pangoFont = createPangoFontForFont(wxfont);
    PangoFontMap* fontMap = pangoFontMap();
    PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap));
    scaled_font = createScaledFontForFont(wxfont); 
#elif __WXMSW__
    cairo_matrix_t sizeMatrix, ctm;
    cairo_matrix_init_identity(&ctm);
    int size = font->platformData().size();
    cairo_matrix_init_scale(&sizeMatrix, size, size);

    cairo_font_options_t* fontOptions = cairo_font_options_create();
    cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
    
    cairo_font_face_t* win_face = cairo_win32_font_face_create_for_hfont((HFONT)wxfont->GetHFONT());
    scaled_font = cairo_scaled_font_create(win_face, &sizeMatrix, &ctm, fontOptions); 
#endif
    ASSERT(scaled_font);

    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
    float offset = point.x();

    for (int i = 0; i < numGlyphs; i++) {
#if wxUSE_PANGO
        glyphs[i].index = pango_font_get_glyph(pangoFont, pangoContext, glyphBuffer.glyphAt(from + i));
#endif
        glyphs[i].x = offset;
        glyphs[i].y = point.y();
        offset += glyphBuffer.advanceAt(from + i);
    }

    cairo_set_source_rgba(cr, color.Red()/255.0, color.Green()/255.0, color.Blue()/255.0, color.Alpha()/255.0);
    cairo_set_scaled_font(cr, scaled_font);
    
    cairo_show_glyphs(cr, glyphs, numGlyphs);

    cairo_scaled_font_destroy(scaled_font);
    gc->PopState();
#else
    wxDC* dc = graphicsContext->platformContext();

    wxFont* wxfont = font->getWxFont();
    if (wxfont && wxfont->IsOk())
        dc->SetFont(*wxfont);
    dc->SetTextForeground(color);

    // convert glyphs to wxString
    GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
    int offset = point.x();
    wxString text = wxEmptyString;
    for (unsigned i = 0; i < numGlyphs; i++) {
        text = text.Append((wxChar)glyphs[i]);
        offset += glyphBuffer.advanceAt(from + i);
    }
    
    // the y point is actually the bottom point of the text, turn it into the top
    float height = font->ascent() - font->descent();
    wxCoord ypoint = (wxCoord) (point.y() - height);
     
    dc->DrawText(text, (wxCoord)point.x(), ypoint);
#endif
}
Exemple #21
0
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
                      const FloatPoint& point) const {
    SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert

    const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
    SkScalar x = SkFloatToScalar(point.x());
    SkScalar y = SkFloatToScalar(point.y());

    // FIXME: text rendering speed:
    // Android has code in their WebCore fork to special case when the
    // GlyphBuffer has no advances other than the defaults. In that case the
    // text drawing can proceed faster. However, it's unclear when those
    // patches may be upstreamed to WebKit so we always use the slower path
    // here.
    const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
    SkPoint* pos = storage.get();
    SkPoint* vPosBegin = storage2.get();
    SkPoint* vPosEnd = storage3.get();

    bool isVertical = font->platformData().orientation() == Vertical;
    for (int i = 0; i < numGlyphs; i++) {
        SkScalar myWidth = SkFloatToScalar(adv[i].width());
        pos[i].set(x, y);
        if (isVertical) {
            vPosBegin[i].set(x + myWidth, y);
            vPosEnd[i].set(x + myWidth, y - myWidth);
        }
        x += myWidth;
        y += SkFloatToScalar(adv[i].height());
    }

    gc->platformContext()->prepareForSoftwareDraw();

    SkCanvas* canvas = gc->platformContext()->canvas();
    TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();

    // We draw text up to two times (once for fill, once for stroke).
    if (textMode & TextModeFill) {
        SkPaint paint;
        gc->platformContext()->setupPaintForFilling(&paint);
        font->platformData().setupPaint(&paint);
        adjustTextRenderMode(&paint, gc->platformContext());
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        paint.setColor(gc->fillColor().rgb());

        if (isVertical) {
            SkPath path;
            for (int i = 0; i < numGlyphs; ++i) {
                path.reset();
                path.moveTo(vPosBegin[i]);
                path.lineTo(vPosEnd[i]);
                canvas->drawTextOnPath(glyphs + i, 2, path, 0, paint);
            }
        } else
            canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
    }

    if ((textMode & TextModeStroke)
        && gc->platformContext()->getStrokeStyle() != NoStroke
        && gc->platformContext()->getStrokeThickness() > 0) {

        SkPaint paint;
        gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
        font->platformData().setupPaint(&paint);
        adjustTextRenderMode(&paint, gc->platformContext());
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        paint.setColor(gc->strokeColor().rgb());

        if (textMode & TextModeFill) {
            // If we also filled, we don't want to draw shadows twice.
            // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
            SkSafeUnref(paint.setLooper(0));
        }

        if (isVertical) {
            SkPath path;
            for (int i = 0; i < numGlyphs; ++i) {
                path.reset();
                path.moveTo(vPosBegin[i]);
                path.lineTo(vPosEnd[i]);
                canvas->drawTextOnPath(glyphs + i, 2, path, 0, paint);
            }
        } else
            canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
    }
}
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
                      const FloatPoint& point) const
{
    // compile-time assert
    SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t));

    if (numGlyphs == 1 && glyphBuffer.glyphAt(from) == 0x3) {
        // Webkit likes to draw end text control command for some reason
        // Just ignore it
        return;
    }

    SkPaint paint;
    if (!setupForText(&paint, gc, font)) {
        return;
    }

    SkScalar                    x = SkFloatToScalar(point.x());
    SkScalar                    y = SkFloatToScalar(point.y());
    const GlyphBufferGlyph*     glyphs = glyphBuffer.glyphs(from);
    const GlyphBufferAdvance*   adv = glyphBuffer.advances(from);
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
    SkPoint*                    pos = storage.get();

    SkCanvas* canvas = gc->platformContext()->recordingCanvas();

    /*  We need an array of [x,y,x,y,x,y,...], but webkit is giving us
        point.xy + [width, height, width, height, ...], so we have to convert
     */

    if (font->platformData().orientation() == Vertical) {
        float yOffset = SkFloatToScalar(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent());
        gc->platformContext()->setTextOffset(FloatSize(0.0f, -yOffset)); // compensate for offset in bounds calculation
        y += yOffset;
    }

    if (EmojiFont::IsAvailable()) {
        // set filtering, to make scaled images look nice(r)
        paint.setFilterBitmap(true);

        SkMatrix rotator;
        rotator.reset();
        if (font->platformData().orientation() == Vertical) {
            canvas->save();
            canvas->rotate(-90);
            rotator.setRotate(90);
        }

        int localIndex = 0;
        int localCount = 0;
        for (int i = 0; i < numGlyphs; i++) {
            if (EmojiFont::IsEmojiGlyph(glyphs[i])) {
                if (localCount) {
                    rotator.mapPoints(&pos[localIndex], localCount);
                    canvas->drawPosText(&glyphs[localIndex],
                                     localCount * sizeof(uint16_t),
                                     &pos[localIndex], paint);
                }
                EmojiFont::Draw(canvas, glyphs[i], x, y, paint);
                // reset local index/count track for "real" glyphs
                localCount = 0;
                localIndex = i + 1;
            } else {
                pos[i].set(x, y);
                localCount += 1;
            }
            x += SkFloatToScalar(adv[i].width());
            y += SkFloatToScalar(adv[i].height());
        }

        // draw the last run of glyphs (if any)
        if (localCount) {
            rotator.mapPoints(&pos[localIndex], localCount);
            canvas->drawPosText(&glyphs[localIndex],
                             localCount * sizeof(uint16_t),
                             &pos[localIndex], paint);

        }

        if (font->platformData().orientation() == Vertical)
            canvas->restore();
    } else {
        for (int i = 0; i < numGlyphs; i++) {
            pos[i].set(x, y);
            y += SkFloatToScalar(adv[i].height());
            x += SkFloatToScalar(adv[i].width());
        }

        if (font->platformData().orientation() == Vertical) {
            canvas->save();
            canvas->rotate(-90);
            SkMatrix rotator;
            rotator.reset();
            rotator.setRotate(90);
            rotator.mapPoints(pos, numGlyphs);
        }
        canvas->drawPosText(glyphs,
            numGlyphs * sizeof(uint16_t), pos, paint);

        if (font->platformData().orientation() == Vertical)
            canvas->restore();
    }

    if (font->platformData().orientation() == Vertical)
        gc->platformContext()->setTextOffset(FloatSize()); // reset to undo above
}
Exemple #23
0
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    cairo_t* cr = context->platformContext();
    cairo_save(cr);

    cairo_set_scaled_font(cr, font->platformData().scaledFont());

    GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);

    float offset = 0.0f;
    for (int i = 0; i < numGlyphs; i++) {
        glyphs[i].x = offset;
        glyphs[i].y = 0.0f;
        offset += glyphBuffer.advanceAt(from + i);
    }

    Color fillColor = context->fillColor();

    // Synthetic Oblique
    if(font->platformData().syntheticOblique()) {
        cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()};
        cairo_transform(cr, &mat);
    } else {
        cairo_translate(cr, point.x(), point.y());
    }

    // Text shadow, inspired by FontMac
    FloatSize shadowOffset;
    float shadowBlur = 0;
    Color shadowColor;
    bool hasShadow = context->textDrawingMode() & cTextFill
                     && context->getShadow(shadowOffset, shadowBlur, shadowColor);

    // TODO: Blur support
    if (hasShadow) {
        // Disable graphics context shadows (not yet implemented) and paint them manually
        context->clearShadow();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        cairo_save(cr);

        float red, green, blue, alpha;
        shadowFillColor.getRGBA(red, green, blue, alpha);
        cairo_set_source_rgba(cr, red, green, blue, alpha);

#if ENABLE(FILTERS)
        cairo_text_extents_t extents;
        cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);

        FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height));
        IntSize shadowBufferSize;
        FloatRect shadowRect;
        float radius = 0;
        context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur);

        // Draw shadow into a new ImageBuffer
        OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
        GraphicsContext* shadowContext = shadowBuffer->context();
        cairo_t* shadowCr = shadowContext->platformContext();

        cairo_translate(shadowCr, radius, extents.height + radius);

        cairo_set_scaled_font(shadowCr, font->platformData().scaledFont());
        cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(shadowCr);
            cairo_translate(shadowCr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
            cairo_restore(shadowCr);
        }
        cairo_translate(cr, 0.0, -extents.height);
        context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius);
#else
        cairo_translate(cr, shadowOffset.width(), shadowOffset.height());
        cairo_show_glyphs(cr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(cr);
            cairo_translate(cr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(cr, glyphs, numGlyphs);
            cairo_restore(cr);
        }
#endif

        cairo_restore(cr);
    }

    if (context->textDrawingMode() & cTextFill) {
        if (context->fillGradient()) {
            cairo_set_source(cr, context->fillGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->fillPattern()) {
            AffineTransform affine;
            cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine);
            cairo_set_source(cr, pattern);
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
            cairo_pattern_destroy(pattern);
        } else {
            float red, green, blue, alpha;
            fillColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        }
        cairo_show_glyphs(cr, glyphs, numGlyphs);
        if (font->syntheticBoldOffset()) {
            cairo_save(cr);
            cairo_translate(cr, font->syntheticBoldOffset(), 0);
            cairo_show_glyphs(cr, glyphs, numGlyphs);
            cairo_restore(cr);
        }
    }

    // Prevent running into a long computation within cairo. If the stroke width is
    // twice the size of the width of the text we will not ask cairo to stroke
    // the text as even one single stroke would cover the full wdth of the text.
    //  See https://bugs.webkit.org/show_bug.cgi?id=33759.
    if (context->textDrawingMode() & cTextStroke && context->strokeThickness() < 2 * offset) {
        if (context->strokeGradient()) {
            cairo_set_source(cr, context->strokeGradient()->platformGradient());
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
        } else if (context->strokePattern()) {
            AffineTransform affine;
            cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine);
            cairo_set_source(cr, pattern);
            if (context->getAlpha() < 1.0f) {
                cairo_push_group(cr);
                cairo_paint_with_alpha(cr, context->getAlpha());
                cairo_pop_group_to_source(cr);
            }
            cairo_pattern_destroy(pattern);
        } else {
            Color strokeColor = context->strokeColor();
            float red, green, blue, alpha;
            strokeColor.getRGBA(red, green, blue, alpha);
            cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
        }
        cairo_glyph_path(cr, glyphs, numGlyphs);
        cairo_set_line_width(cr, context->strokeThickness());
        cairo_stroke(cr);
    }

    // Re-enable the platform shadow we disabled earlier
    if (hasShadow)
        context->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace);

    cairo_restore(cr);
}
Exemple #24
0
// TODO: This needs to be split into helper functions to better scope the
// inputs/outputs, and reduce duplicate code.
// This issue is tracked in https://bugs.webkit.org/show_bug.cgi?id=62989
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
                      const FloatPoint& point) const {
    COMPILE_ASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t), GlyphBufferGlyphSize_equals_uint16_t);

    bool shouldSmoothFonts = true;
    bool shouldAntialias = true;
    
    switch (fontDescription().fontSmoothing()) {
    case Antialiased:
        shouldSmoothFonts = false;
        break;
    case SubpixelAntialiased:
        break;
    case NoSmoothing:
        shouldAntialias = false;
        shouldSmoothFonts = false;
        break;
    case AutoSmoothing:
        // For the AutoSmooth case, don't do anything! Keep the default settings.
        break; 
    }
    
    if (!shouldUseSmoothing() || PlatformSupport::layoutTestMode())
        shouldSmoothFonts = false;

    const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
    SkScalar x = SkFloatToScalar(point.x());
    SkScalar y = SkFloatToScalar(point.y());

    if (font->platformData().orientation() == Vertical)
        y += SkFloatToScalar(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent());
    // FIXME: text rendering speed:
    // Android has code in their WebCore fork to special case when the
    // GlyphBuffer has no advances other than the defaults. In that case the
    // text drawing can proceed faster. However, it's unclear when those
    // patches may be upstreamed to WebKit so we always use the slower path
    // here.
    const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
    SkPoint* pos = storage.get();

    for (int i = 0; i < numGlyphs; i++) {
        pos[i].set(x, y);
        x += SkFloatToScalar(adv[i].width);
        y += SkFloatToScalar(adv[i].height);
    }

    SkCanvas* canvas = gc->platformContext()->canvas();
    if (font->platformData().orientation() == Vertical) {
        canvas->save();
        canvas->rotate(-90);
        SkMatrix rotator;
        rotator.reset();
        rotator.setRotate(90);
        rotator.mapPoints(pos, numGlyphs);
    }
    TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();

    // We draw text up to two times (once for fill, once for stroke).
    if (textMode & TextModeFill) {
        SkPaint paint;
        gc->platformContext()->setupPaintForFilling(&paint);
        setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts);
        gc->platformContext()->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint);
    }

    if ((textMode & TextModeStroke)
        && gc->platformContext()->getStrokeStyle() != NoStroke
        && gc->platformContext()->getStrokeThickness() > 0) {

        SkPaint paint;
        gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
        setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts);
        gc->platformContext()->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        if (textMode & TextModeFill) {
            // If we also filled, we don't want to draw shadows twice.
            // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
            paint.setLooper(0);
        }

        canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint);
    }
    if (font->platformData().orientation() == Vertical)
        canvas->restore();
}
Exemple #25
0
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, 
                      int from, int numGlyphs, const FloatPoint& point) const
{
    CGContextRef cgContext = graphicsContext->platformContext();
    bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();

    if (font->platformData().useGDI()) {
        static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs();
        if (!canUsePlatformNativeGlyphs || !shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) {
            drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
            return;
        }
    }

    uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing);

    const FontPlatformData& platformData = font->platformData();

    CGContextSetFont(cgContext, platformData.cgFont());

    CGAffineTransform matrix = CGAffineTransformIdentity;
    matrix.b = -matrix.b;
    matrix.d = -matrix.d;

    if (platformData.syntheticOblique()) {
        static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f);
        matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0));
    }

    CGContextSetTextMatrix(cgContext, matrix);

    // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
    FloatSize translation = glyphBuffer.offsetAt(from);

    CGContextSetFontSize(cgContext, platformData.size());
    wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI());

    IntSize shadowSize;
    int shadowBlur;
    Color shadowColor;
    graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor);

    bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur;
    if (hasSimpleShadow) {
        // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
        graphicsContext->clearShadow();
        Color fillColor = graphicsContext->fillColor();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        graphicsContext->setFillColor(shadowFillColor);
        CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height());
        CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
        if (font->m_syntheticBoldOffset) {
            CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + translation.height() + shadowSize.height());
            CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
        }
        graphicsContext->setFillColor(fillColor);
    }

    CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
    CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    if (font->m_syntheticBoldOffset) {
        CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->m_syntheticBoldOffset, point.y() + translation.height());
        CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    }

    if (hasSimpleShadow)
        graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor);

    wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
}
Exemple #26
0
void Font::drawGlyphs(GraphicsContext* graphicsContext,
                      const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,
                      int from,
                      int numGlyphs,
                      const FloatPoint& point) const
{
    SkColor color = graphicsContext->effectiveFillColor();
    unsigned char alpha = SkColorGetA(color);
    // Skip 100% transparent text; no need to draw anything.
    if (!alpha && graphicsContext->strokeStyle() == NoStroke && !graphicsContext->hasShadow())
        return;

    // We draw the glyphs in chunks to avoid having to do a heap allocation for
    // the arrays of characters and advances.
    const int kMaxBufferLength = 256;
    Vector<int, kMaxBufferLength> advances;
    int glyphIndex = 0;  // The starting glyph of the current chunk.

    float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph.
#if ENABLE(OPENTYPE_VERTICAL)
    const OpenTypeVerticalData* verticalData = font->verticalData();
    if (verticalData) {
        Vector<FloatPoint, kMaxBufferLength> translations;
        Vector<GOFFSET, kMaxBufferLength> offsets;

        // Skia doesn't have matrix for glyph coordinate space, so we rotate back the CTM.
        AffineTransform savedMatrix = graphicsContext->getCTM();
        graphicsContext->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y()));
        graphicsContext->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y()));

        const FontMetrics& metrics = font->fontMetrics();
        SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline));
        while (glyphIndex < numGlyphs) {
            // How many chars will be in this chunk?
            int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);

            const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex);
            translations.resize(curLen);
            verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], curLen, reinterpret_cast<float*>(&translations[0]));
            // To position glyphs vertically, we use offsets instead of advances.
            advances.resize(curLen);
            advances.fill(0);
            offsets.resize(curLen);
            float currentWidth = 0;
            for (int i = 0; i < curLen; ++i, ++glyphIndex) {
                offsets[i].du = lroundf(translations[i].x());
                offsets[i].dv = -lroundf(currentWidth - translations[i].y());
                currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
            }
            SkPoint origin;
            origin.set(verticalOriginX, SkFloatToScalar(point.y() + horizontalOffset - point.x()));
            horizontalOffset += currentWidth;
            paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], &offsets[0], &origin);
        }

        graphicsContext->setCTM(savedMatrix);
        return;
    }
#endif

    // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position
    // of each glyph in floating point units and rounds to integer advances at the last possible moment.

    int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered.
    Vector<WORD, kMaxBufferLength> glyphs;
    while (glyphIndex < numGlyphs) {
        // How many chars will be in this chunk?
        int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
        glyphs.resize(curLen);
        advances.resize(curLen);

        float currentWidth = 0;
        for (int i = 0; i < curLen; ++i, ++glyphIndex) {
            glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
            horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex);
            advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded;
            lastHorizontalOffsetRounded += advances[i];
            currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
            
            // Bug 26088 - very large positive or negative runs can fail to
            // render so we clamp the size here. In the specs, negative
            // letter-spacing is implementation-defined, so this should be
            // fine, and it matches Safari's implementation. The call actually
            // seems to crash if kMaxNegativeRun is set to somewhere around
            // -32830, so we give ourselves a little breathing room.
            const int maxNegativeRun = -32768;
            const int maxPositiveRun =  32768;
            if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) 
                advances[i] = 0;
        }

        SkPoint origin = point;
        origin.fX += SkFloatToScalar(horizontalOffset - point.x() - currentWidth);
        paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], 0, &origin);
    }
}
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    TextRun run(glyphBuffer.glyphs(from), numGlyphs, false, 0, 0, false, false, false, false);
    drawComplexText(context, run, point, 0, numGlyphs);
}
Exemple #28
0
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
    const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs,
    const FloatPoint& point, const FloatRect& textRect) const
{
    SkScalar x = SkFloatToScalar(point.x());
    SkScalar y = SkFloatToScalar(point.y());

    const OpenTypeVerticalData* verticalData = font->verticalData();
    if (font->platformData().orientation() == Vertical && verticalData) {
        SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
        SkPoint* pos = storage.get();

        AffineTransform savedMatrix = gc->getCTM();
        gc->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y()));
        gc->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y()));

        const unsigned kMaxBufferLength = 256;
        Vector<FloatPoint, kMaxBufferLength> translations;

        const FontMetrics& metrics = font->fontMetrics();
        SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline));
        float horizontalOffset = point.x();

        unsigned glyphIndex = 0;
        while (glyphIndex < numGlyphs) {
            unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphIndex);

            const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex);
            translations.resize(chunkLength);
            verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chunkLength, reinterpret_cast<float*>(&translations[0]));

            x = verticalOriginX;
            y = SkFloatToScalar(point.y() + horizontalOffset - point.x());

            float currentWidth = 0;
            for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) {
                pos[i].set(
                    x + SkIntToScalar(lroundf(translations[i].x())),
                    y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y())));
                currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
            }
            horizontalOffset += currentWidth;
            paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect);
        }

        gc->setCTM(savedMatrix);
        return;
    }

    if (!glyphBuffer.hasOffsets()) {
        SkAutoSTMalloc<64, SkScalar> storage(numGlyphs);
        SkScalar* xpos = storage.get();
        const float* adv = glyphBuffer.advances(from);
        for (unsigned i = 0; i < numGlyphs; i++) {
            xpos[i] = x;
            x += SkFloatToScalar(adv[i]);
        }
        const Glyph* glyphs = glyphBuffer.glyphs(from);
        paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar(y), textRect);
        return;
    }

    // FIXME: text rendering speed:
    // Android has code in their WebCore fork to special case when the
    // GlyphBuffer has no advances other than the defaults. In that case the
    // text drawing can proceed faster. However, it's unclear when those
    // patches may be upstreamed to WebKit so we always use the slower path
    // here.
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
    SkPoint* pos = storage.get();
    const FloatSize* offsets = glyphBuffer.offsets(from);
    const float* advances = glyphBuffer.advances(from);
    SkScalar advanceSoFar = SkFloatToScalar(0);
    for (unsigned i = 0; i < numGlyphs; i++) {
        pos[i].set(
            x + SkFloatToScalar(offsets[i].width()) + advanceSoFar,
            y + SkFloatToScalar(offsets[i].height()));
        advanceSoFar += SkFloatToScalar(advances[i]);
    }

    const Glyph* glyphs = glyphBuffer.glyphs(from);
    paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect);
}
Exemple #29
0
// We need to draw the glyphBuffer glyphs/advances with the pSimpleFontData font onto the 
// pGraphicsContext pSurface. We draw glyphCount glyphs starting at the glyphIndexBegin.
void Font::drawGlyphs(GraphicsContext* pGraphicsContext, const SimpleFontData* pSimpleFontData, const GlyphBuffer& glyphBuffer,
                        int glyphIndexBegin, int glyphCount, const FloatPoint& point) const
{
    // 11/09/09 CSidhall Added notify start of process to user
	NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusStarted);
	
    #if defined(EA_DEBUG) && defined(AUTHOR_PPEDRIANA_DISABLED) && defined(EA_PLATFORM_WINDOWS)
        TraceGlyphBufferToString(pSimpleFontData, glyphBuffer, glyphIndexBegin, glyphCount, point);
    #endif

    GlyphBufferGlyph*               glyphs      = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(glyphIndexBegin));
    float                           offset      = 0;   
    int                             x_offset    = 0;
    EA::Internal::IFont*            pFont       = pSimpleFontData->m_font.mpFont;
    EA::Internal::IGlyphCache*      pGlyphCache = EA::WebKit::GetGlyphCache(); 
    EAW_ASSERT_MSG(pGlyphCache, "GlyphCache is not set");
	if(!pGlyphCache)
	{
		NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusEnded);
		return;
	}
    
    EA::Internal::ITextureInfo*     pTI         = pGlyphCache->GetTextureInfo(0); // Right now we hard-code usage of what is the only texture.
	EAW_ASSERT_MSG(pTI, "GlyphCache is not initialized with enough number of textures");
	if(!pTI)
	{
		NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusEnded);
		return;
	}

	const int32_t                   textureSize = (int32_t)pTI->GetSize();
    EA::Internal::IGlyphTextureInfo gti;
    EA::Internal::GlyphMetrics      glyphMetrics;
    GlyphDrawInfoArray              gdiArray((size_t)(unsigned)glyphCount);

    // Walk through the list of glyphs and build up render info for each one.
    for (int i = 0; i < glyphCount; i++)
    {
        EA::Internal::GlyphId g = glyphs[i];

        if(!pFont->GetGlyphMetrics(g, glyphMetrics))
        {
            EAW_ASSERT_MSG(false, "Font::drawGlyphs: invalid glyph/Font combo.");
            pFont->GetGlyphIds(L"?", 1, &g, true);
            pFont->GetGlyphMetrics(g, glyphMetrics);
        }

        if(!pGlyphCache->GetGlyphTextureInfo(pFont, g, gti))
        {
            const EA::Internal::GlyphBitmap* pGlyphBitmap;

            if(pFont->RenderGlyphBitmap(&pGlyphBitmap, g))
            {
                if(pGlyphCache->AddGlyphTexture(pFont, g, pGlyphBitmap->mpData, pGlyphBitmap->mnWidth, pGlyphBitmap->mnHeight, 
                                                              pGlyphBitmap->mnStride, (uint32_t)pGlyphBitmap->mBitmapFormat, gti))
                {
                    pGlyphCache->EndUpdate(gti.mpTextureInfo);
                }
                else
                {
                    EAW_ASSERT_MSG(false, "Font::drawGlyphs: AddGlyphTexture failed.");
                    gti.mX1 = gti.mX2 = 0; // Make this an empty glyph. Normally this should never execute.
                }

                pFont->DoneGlyphBitmap(pGlyphBitmap);
            } 
            else
            {
                EAW_ASSERT_MSG(false, "Font::drawGlyphs: invalid glyph/Font combo.");
                gti.mX1 = gti.mX2 = 0; // Make this an empty glyph. Normally this should never execute.
            }
        }

        // Apply kerning.
        // Note by Paul Pedriana: Can we really apply kerning here at the render stage without it looking 
        // wrong? It seems to me this cannot work unless kerning is also taken into account at the 
        // layout stage. To do: See if in fact kerning is taken into account at the layout stage.
        EA::Internal::Kerning kerning;

        if((i > 0) && pFont->GetKerning(glyphs[i - 1], g, kerning, 0))
            offset += kerning.mfKernX;

        // The values we calculate here are relative to the current pen position at the 
        // baseline position of [xoffset, 0], where +X is rightward and +Y is upward.
        gdiArray[i].x1 = (int)(offset + glyphMetrics.mfHBearingX);
        gdiArray[i].x2 = (int)(offset + glyphMetrics.mfHBearingX + glyphMetrics.mfSizeX);
        gdiArray[i].y1 = (int)(glyphMetrics.mfHBearingY);
        gdiArray[i].y2 = (int)(glyphMetrics.mfHBearingY - glyphMetrics.mfSizeY);
        gdiArray[i].tx = (int)(gti.mX1 * textureSize); // Convert [0..1] to [0..textureSize]
        gdiArray[i].ty = (int)(gti.mY1 * textureSize);

        // advanceAt should return a value that is usually equivalent to glyphMetrics.mfHAdvanceX, at least 
        // for most simple Western text. A case where it would be different would be Arabic combining glyphs,
        // and custom kerning, though kerning adjustments are handled above.
        offset += glyphBuffer.advanceAt(glyphIndexBegin + i);
    
        // Free wrapper
        if(gti.mpTextureInfo)
            gti.mpTextureInfo->DestroyWrapper();
    
    }

	// Find the X and Y minima and maxima of the glyph boxes.
    // To do: We can improve the efficiency of this code in a couple of ways, including moving the 
    // min/max tests up into the glyphMetrics code above.
    int xMin = gdiArray[0].x1;
    int xMax = gdiArray[0].x2;
    int yMin = gdiArray[0].y2;    // y2 is min because y goes upward.
    int yMax = gdiArray[0].y1;

    for (GlyphDrawInfoArray::const_iterator it = gdiArray.begin(); it != gdiArray.end(); ++it)
    {
        const GlyphDrawInfo& gdi = *it;

        // We assume tha x1 is always <= x2.
        if (gdi.x1 < xMin)
            xMin = gdi.x1;

        if (gdi.x2 > xMax)
            xMax = gdi.x2;

        // if (gdi.y1 < yMin)  // We normally don't need this check, because y2 will usually (or always?) be less than y1.
        //     yMin = gdi.y1;

        if (gdi.y2 < yMin)
            yMin = gdi.y2;

        if (gdi.y1 > yMax)
            yMax = gdi.y1;

        // if (gdi.y2 > yMax)  // We normally don't need this check, because y1 will usually (or always?) be greater than y2.
        //     yMax = gdi.y2;
    }

    const uint16_t destWidth  = (abs(xMin) + xMax);  // abs(xMin) because it's possible the left of the first glyph is to the left of the origin. Note by Paul Pedriana: Shouldn't this instead be (xMax - min(xMin, 0))?
    const uint16_t destHeight = (yMax - yMin);

    if(destWidth && destHeight)  // (If we are drawing just space chars (which often happens), then destWidth and/or destHeight will be zero)
    {
        // Question by Paul Pedriana: What is the following code doing? I copied this from the 
        // WebKit Freetype equivalent of this function assuming it must be useful. It seems to 
        // me that it is chopping off any glyph pixels to the left of zero. This is probably 
        // going to usually be OK, because it is abnormal for the first char of just about any
        // written language to be a combining char (and thus drawn to the left of the pen position).
        if (gdiArray[0].x1 < 0)
        {
            x_offset = gdiArray[0].x1;
            gdiArray[0].x1 = 0;
        }

        EA::Raster::Surface* const pSurface = pGraphicsContext->platformContext();
        const Color                penColor = pGraphicsContext->fillColor();

        // Write the glyphs into a linear buffer.
        // To consider: See if it's possible to often get away with using stack space for this by
        //              using Vector<uint32_t, N> in order to avoid a memory allocation. A typical
        //              width is ~400 pixels and a typical height ~16 pixels, which is 25600 bytes.
        //              So unless the string is small there won't be any benefit to this.
        Vector<uint32_t> glyphRGBABuffer(destWidth * destHeight);
        const int        penA   = penColor.alpha();
        const int        penR   = penColor.red();
        const int        penG   = penColor.green();
        const int        penB   = penColor.blue();
        const int        penRGB = (penR << 16) | (penG << 8) | penB;

        glyphRGBABuffer.fill(0);

		for (int i = 0; i < glyphCount; i++)
        {
			const GlyphDrawInfo& gdi         = gdiArray[i];
            const uint8_t*       pGlyphAlpha = (pTI->GetData()) + (gdi.ty * pTI->GetStride()) + gdi.tx;
            const int            yOffset     = (destHeight + yMin) - gdi.y1;
			// Note by Arpit Baldeva: Old index calculation below caused a memory overrun(or I should say underrun on http://get.adobe.com/flashplayer/).
			// Basically, yOffset * destWidth) + gdi.x1 could end up being negative if the yOffset is 0 and gdi.x1 is negative. Since I do want
			// to make sure that index is positive, I just force it to be at least 0. There is not enough understanding about this code as of now
			// and Paul said that he would take a look at this along with other Font problems he is currently looking at.
			const int bufferIndex = (yOffset * destWidth) + gdi.x1;
			EAW_ASSERT_FORMATTED(bufferIndex>=0, "Buffer Index is negative. This would corrupt memory. yOffset:%d,destWidth:%u,gdi.x1:%d",yOffset,destWidth,gdi.x1);
			uint32_t*            pDestColor  = glyphRGBABuffer.data() + (bufferIndex >= 0 ? bufferIndex : 0);//Old Index calculation- (yOffset * destWidth) + gdi.x1;
            const int            glyphWidth  = (gdi.x2 - gdi.x1);
            const int            glyphHeight = (gdi.y1 - gdi.y2);

			for (int y = 0; y < glyphHeight; ++y)
            {
				for (int x = 0; x < glyphWidth; ++x)
				{
					//+ 1/5/10 CSidhall - When building the text string texture map, kerning can make certain letters overlap and stomp over the alpha of previous letters so 
                    // we need to preserve texels that were aleady set. Should be able to OR herer because we have a clean buffer and penRGB is the same.
                    // Old code:
                    // pDestColor[x] = ((penA * pGlyphAlpha[x] / 255) << 24) | penRGB;
                    // New code:
                    pDestColor[x] |= ((penA * pGlyphAlpha[x] / 255) << 24) | penRGB;
                    // -CS
				}
                
                pDestColor  += destWidth;
                pGlyphAlpha += pTI->GetStride();
            }

        }

        // It would probably be faster if we kept around a surface for multiple usage instead of 
        // continually recreating this one.
        EA::Raster::Surface* const pGlyphSurface = EA::Raster::CreateSurface((void*)glyphRGBABuffer.data(), destWidth, destHeight, destWidth * 4, EA::Raster::kPixelFormatTypeARGB, false, false);
        EA::Raster::Rect rectSrc;
        EA::Raster::Rect rectDest;

        rectSrc.w  = destWidth;
        rectSrc.h  = destHeight;
        rectSrc.x  = 0;
        rectSrc.y  = 0;
        rectDest.x = (int)point.x() + x_offset + pGraphicsContext->origin().width();
        rectDest.y = (int)point.y() - yMax     + pGraphicsContext->origin().height();

        if (pGraphicsContext->transparencyLayer() == 1.0)
            EA::Raster::Blit(pGlyphSurface, &rectSrc, pSurface, &rectDest);
        else
        {
            const float fTransparency = pGraphicsContext->transparencyLayer();
            EA::Raster::Surface* const pSurfaceWithAlpha = EA::Raster::CreateTransparentSurface(pGlyphSurface, (int)(fTransparency * 255));
            EA::Raster::Blit(pSurfaceWithAlpha, &rectSrc, pSurface, &rectDest);
            EA::Raster::DestroySurface(pSurfaceWithAlpha);
        }

        EA::Raster::DestroySurface(pGlyphSurface);
    }
    pTI->DestroyWrapper();

	NOTIFY_PROCESS_STATUS(EA::WebKit::kVProcessTypeDrawGlyph, EA::WebKit::kVProcessStatusEnded);
}