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