#include "config.h"
#include "Font.h"
#include "AffineTransform.h"
#include "CairoUtilities.h"
#include "ContextShadow.h"
#include "GlyphBuffer.h"
#include "Gradient.h"
#include "GraphicsContext.h"
#include "PlatformContextCairo.h"
#include "ImageBuffer.h"
#include "Pattern.h"
#include "SimpleFontData.h"
namespace WebCore {
static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font, const FloatPoint& point)
{
static const float syntheticObliqueSkew = -tanf(14 * acosf(0) / 90);
cairo_set_scaled_font(context, font->platformData().scaledFont());
if (font->platformData().syntheticOblique()) {
cairo_matrix_t mat = {1, 0, syntheticObliqueSkew, 1, point.x(), point.y()};
cairo_transform(context, &mat);
} else
cairo_translate(context, point.x(), point.y());
}
static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
{
cairo_show_glyphs(context, glyphs, numGlyphs);
if (font->syntheticBoldOffset()) {
cairo_translate(context, font->syntheticBoldOffset(), 0);
cairo_show_glyphs(context, glyphs, numGlyphs);
cairo_translate(context, -font->syntheticBoldOffset(), 0);
}
}
static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
{
ContextShadow* shadow = graphicsContext->contextShadow();
ASSERT(shadow);
if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow)
return;
if (!shadow->mustUseContextShadow(graphicsContext)) {
cairo_t* context = graphicsContext->platformContext()->cr();
cairo_save(context);
cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height());
setSourceRGBAFromColor(context, shadow->m_color);
prepareContextForGlyphDrawing(context, font, point);
cairo_show_glyphs(context, glyphs, numGlyphs);
cairo_restore(context);
return;
}
cairo_text_extents_t extents;
cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents);
FloatRect fontExtentsRect(point.x(), point.y() - extents.height, extents.width, extents.height);
cairo_t* shadowContext = shadow->beginShadowLayer(graphicsContext, fontExtentsRect);
if (shadowContext) {
prepareContextForGlyphDrawing(shadowContext, font, point);
drawGlyphsToContext(shadowContext, font, glyphs, numGlyphs);
shadow->endShadowLayer(graphicsContext);
}
}
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
int from, int numGlyphs, const FloatPoint& point) const
{
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);
}
PlatformContextCairo* platformContext = context->platformContext();
drawGlyphsShadow(context, point, font, glyphs, numGlyphs);
cairo_t* cr = platformContext->cr();
cairo_save(cr);
prepareContextForGlyphDrawing(cr, font, point);
if (context->textDrawingMode() & TextModeFill) {
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;
context->fillColor().getRGBA(red, green, blue, alpha);
cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
}
drawGlyphsToContext(cr, font, glyphs, numGlyphs);
}
if (context->textDrawingMode() & TextModeStroke && 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 {
float red, green, blue, alpha;
context->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);
}
cairo_restore(cr);
}
}