Home | History | Annotate | Download | only in cairo
      1 /*
      2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
      3  * Copyright (C) 2006 Michael Emmel mike.emmel (at) gmail.com
      4  * Copyright (C) 2007, 2008 Alp Toker <alp (at) atoker.com>
      5  * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org>
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "Font.h"
     31 
     32 #include "AffineTransform.h"
     33 #include "GlyphBuffer.h"
     34 #include "Gradient.h"
     35 #include "GraphicsContext.h"
     36 #include "ImageBuffer.h"
     37 #include "Pattern.h"
     38 #include "SimpleFontData.h"
     39 
     40 #define SYNTHETIC_OBLIQUE_ANGLE 14
     41 
     42 namespace WebCore {
     43 
     44 void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
     45                       int from, int numGlyphs, const FloatPoint& point) const
     46 {
     47     cairo_t* cr = context->platformContext();
     48     cairo_save(cr);
     49 
     50     cairo_set_scaled_font(cr, font->platformData().scaledFont());
     51 
     52     GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
     53 
     54     float offset = 0.0f;
     55     for (int i = 0; i < numGlyphs; i++) {
     56         glyphs[i].x = offset;
     57         glyphs[i].y = 0.0f;
     58         offset += glyphBuffer.advanceAt(from + i);
     59     }
     60 
     61     Color fillColor = context->fillColor();
     62 
     63     // Synthetic Oblique
     64     if(font->platformData().syntheticOblique()) {
     65         cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()};
     66         cairo_transform(cr, &mat);
     67     } else {
     68         cairo_translate(cr, point.x(), point.y());
     69     }
     70 
     71     // Text shadow, inspired by FontMac
     72     IntSize shadowSize;
     73     int shadowBlur = 0;
     74     Color shadowColor;
     75     bool hasShadow = context->textDrawingMode() == cTextFill &&
     76         context->getShadow(shadowSize, shadowBlur, shadowColor);
     77 
     78     // TODO: Blur support
     79     if (hasShadow) {
     80         // Disable graphics context shadows (not yet implemented) and paint them manually
     81         context->clearShadow();
     82         Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
     83         cairo_save(cr);
     84 
     85         float red, green, blue, alpha;
     86         shadowFillColor.getRGBA(red, green, blue, alpha);
     87         cairo_set_source_rgba(cr, red, green, blue, alpha);
     88 
     89 #if ENABLE(FILTERS)
     90         cairo_text_extents_t extents;
     91         cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);
     92 
     93         FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height));
     94         IntSize shadowBufferSize;
     95         FloatRect shadowRect;
     96         float kernelSize = 0.f;
     97         GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur);
     98 
     99         // Draw shadow into a new ImageBuffer
    100         OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize);
    101         GraphicsContext* shadowContext = shadowBuffer->context();
    102         cairo_t* shadowCr = shadowContext->platformContext();
    103 
    104         cairo_translate(shadowCr, kernelSize, extents.height + kernelSize);
    105 
    106         cairo_set_scaled_font(shadowCr, font->platformData().scaledFont());
    107         cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
    108         if (font->syntheticBoldOffset()) {
    109             cairo_save(shadowCr);
    110             cairo_translate(shadowCr, font->syntheticBoldOffset(), 0);
    111             cairo_show_glyphs(shadowCr, glyphs, numGlyphs);
    112             cairo_restore(shadowCr);
    113         }
    114         cairo_translate(cr, 0.0, -extents.height);
    115         context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize);
    116 #else
    117         cairo_translate(cr, shadowSize.width(), shadowSize.height());
    118         cairo_show_glyphs(cr, glyphs, numGlyphs);
    119         if (font->syntheticBoldOffset()) {
    120             cairo_save(cr);
    121             cairo_translate(cr, font->syntheticBoldOffset(), 0);
    122             cairo_show_glyphs(cr, glyphs, numGlyphs);
    123             cairo_restore(cr);
    124         }
    125 #endif
    126 
    127         cairo_restore(cr);
    128     }
    129 
    130     if (context->textDrawingMode() & cTextFill) {
    131         if (context->fillGradient()) {
    132             cairo_set_source(cr, context->fillGradient()->platformGradient());
    133             if (context->getAlpha() < 1.0f) {
    134                 cairo_push_group(cr);
    135                 cairo_paint_with_alpha(cr, context->getAlpha());
    136                 cairo_pop_group_to_source(cr);
    137             }
    138         } else if (context->fillPattern()) {
    139             AffineTransform affine;
    140             cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine));
    141             if (context->getAlpha() < 1.0f) {
    142                 cairo_push_group(cr);
    143                 cairo_paint_with_alpha(cr, context->getAlpha());
    144                 cairo_pop_group_to_source(cr);
    145             }
    146         } else {
    147             float red, green, blue, alpha;
    148             fillColor.getRGBA(red, green, blue, alpha);
    149             cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
    150         }
    151         cairo_show_glyphs(cr, glyphs, numGlyphs);
    152         if (font->syntheticBoldOffset()) {
    153             cairo_save(cr);
    154             cairo_translate(cr, font->syntheticBoldOffset(), 0);
    155             cairo_show_glyphs(cr, glyphs, numGlyphs);
    156             cairo_restore(cr);
    157         }
    158     }
    159 
    160     if (context->textDrawingMode() & cTextStroke) {
    161         if (context->strokeGradient()) {
    162             cairo_set_source(cr, context->strokeGradient()->platformGradient());
    163             if (context->getAlpha() < 1.0f) {
    164                 cairo_push_group(cr);
    165                 cairo_paint_with_alpha(cr, context->getAlpha());
    166                 cairo_pop_group_to_source(cr);
    167             }
    168         } else if (context->strokePattern()) {
    169             AffineTransform affine;
    170             cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine));
    171             if (context->getAlpha() < 1.0f) {
    172                 cairo_push_group(cr);
    173                 cairo_paint_with_alpha(cr, context->getAlpha());
    174                 cairo_pop_group_to_source(cr);
    175             }
    176         } else {
    177             Color strokeColor = context->strokeColor();
    178             float red, green, blue, alpha;
    179             strokeColor.getRGBA(red, green, blue, alpha);
    180             cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
    181         }
    182         cairo_glyph_path(cr, glyphs, numGlyphs);
    183         cairo_set_line_width(cr, context->strokeThickness());
    184         cairo_stroke(cr);
    185     }
    186 
    187     // Re-enable the platform shadow we disabled earlier
    188     if (hasShadow)
    189         context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace);
    190 
    191     cairo_restore(cr);
    192 }
    193 
    194 }
    195