/* sdl-freetype, a text rendering library for SDL. * Copyright (C) 2006 luojinghua * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * THANKS FOR ALL CAIRO AUTHORS, MOST OF IDEAS AND IMPLEMENT DTAILS ARE * STOLEN FROM CAIRO. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sdl-glyph-render.h" #ifdef HAVE_SDL #include #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif static void sdl_freetype_rect_intersect (SDL_Rect * dest, SDL_Rect * src) { int x1, y1, x2, y2; x1 = MAX (dest->x, src->x); y1 = MAX (dest->y, src->y); x2 = MIN (dest->x + dest->w, src->x + src->w); y2 = MIN (dest->y + dest->h, src->y + src->h); if (x1 >= x2 || y1 >= y2) { dest->x = 0; dest->y = 0; dest->w = 0; dest->h = 0; } else { dest->x = x1; dest->y = y1; dest->w = x2 - x1; dest->h = y2 - y1; } } typedef unsigned int CARD32; /* * x_c = (x_c * a) / 255 */ #define FbByteMul(x, a) do { \ CARD32 t = ((x & 0xff00ff) * a) + 0x800080; \ t = (t + ((t >> 8) & 0xff00ff)) >> 8; \ t &= 0xff00ff; \ \ x = (((x >> 8) & 0xff00ff) * a) + 0x800080; \ x = (x + ((x >> 8) & 0xff00ff)); \ x &= 0xff00ff00; \ x += t; \ } while (0) /* * x_c = (x_c * a + y_c * b) / 255 */ #define FbByteAddMul(x, a, y, b) do { \ CARD32 t; \ CARD32 r = (x >> 24) * a + (y >> 24) * b + 0x80; \ r += (r >> 8); \ r >>= 8; \ \ t = (x & 0xff00) * a + (y & 0xff00) * b + 0x8000; \ t += (t >> 8); \ t >>= 16; \ \ t |= r << 16; \ t |= 0x1000100 - ((t >> 8) & 0xff00ff); \ t &= 0xff00ff; \ t <<= 8; \ \ r = ((x >> 16) & 0xff) * a + ((y >> 16) & 0xff) * b + 0x80; \ r += (r >> 8); \ r >>= 8; \ \ x = (x & 0xff) * a + (y & 0xff) * b + 0x80; \ x += (x >> 8); \ x >>= 8; \ x |= r << 16; \ x |= 0x1000100 - ((x >> 8) & 0xff00ff); \ x &= 0xff00ff; \ x |= t; \ } while (0) /** * component-alpha Over: * srcv.A = src.A * mask.A * srcv.R = src.R * mask.A * srcv.G = src.G * mask.A * srcv.B = src.B * mask.A * * srca.A = src.A * mask.A * srca.R = src.A * mask.R * srca.G = src.A * mask.G * srca.B = src.A * mask.B * * dst.A = srcv.A + (1 - srca.A) * dst.A * dst.R = srcv.R + (1 - srca.R) * dst.R * dst.G = srcv.G + (1 - srca.G) * dst.G * dst.B = srcv.B + (1 - srca.B) * dst.B * * Expanded, that's: * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A * dst.R = src.R * mask.A + (1 - (src.A * mask.R)) * dst.R * dst.G = src.G * mask.A + (1 - (src.A * mask.G)) * dst.G * dst.B = src.B * mask.A + (1 - (src.A * mask.B)) * dst.B **/ static unsigned int sdl_freetype_component_alpha_over (CARD32 sc, CARD32 sa, CARD32 mc, CARD32 ma, CARD32 dc) { CARD32 c0, c1; c1 = sa; FbByteMul (c1, mc); c1 = 255 - c1; c0 = sc; FbByteAddMul (c0, ma, c1, dc); return c0; } static sdl_freetype_error_t sdl_freetype_glyph_composite (sdl_freetype_font_t * font, SDL_Surface * dst_surface, unsigned int r, unsigned int g, unsigned int b, unsigned int a, int x, int y, const FT_Bitmap * bitmap, int x_offset, int y_offset) { SDL_Surface * surface; SDL_Rect rect, drect, srect; unsigned int rmask, gmask, bmask, amask; unsigned char * src; unsigned int * dst; int i, j; unsigned int color; if (!dst_surface) return SDL_FREETYPE_ERR_INVALID_VALUE; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #else rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #endif rect.x = x + x_offset; rect.y = y + y_offset; rect.w = bitmap->width; rect.h = bitmap->rows; drect.x = 0; drect.y = 0; drect.w = dst_surface->w; drect.h = dst_surface->h; sdl_freetype_rect_intersect (&drect, &rect); /* nothing to do */ if (!drect.w || !drect.h) return SDL_FREETYPE_ERR_OK; srect.x = drect.x - rect.x; srect.y = drect.y - rect.y; srect.w = drect.w; srect.h = drect.h; surface = SDL_CreateRGBSurface (SDL_SWSURFACE | SDL_SRCALPHA, bitmap->width, bitmap->rows, 32, rmask, gmask, bmask, amask); if (!surface) return -1; switch (bitmap->pixel_mode) { case FT_PIXEL_MODE_MONO: src = bitmap->buffer; dst = surface->pixels; color = r << 24 | g << 16 | b << 8 | a; for (i = 0; i < bitmap->rows; i++) { for (j = 0; j < bitmap->width; j++) { if (src[(j >> 3)] & (0x80 >> (j & 7))) { dst[j] = color; } else { dst[j] = 0; } } src += bitmap->pitch; dst = (unsigned int *)((unsigned char *)dst + surface->pitch); } break; case FT_PIXEL_MODE_GRAY: src = bitmap->buffer; dst = surface->pixels; color = r << 24 | g << 16 | b << 8; for (i = 0; i < bitmap->rows; i++) { for (j = 0; j < bitmap->width; j++) dst[j] = color | ((a * src[j]) / 255); src += bitmap->pitch; dst = (unsigned int *)((unsigned char *)dst + surface->pitch); } break; case FT_PIXEL_MODE_LCD: src = bitmap->buffer; /** * src is the user specified color(r, g, b, a) * mask is the glyph bitmap **/ /** * It's deadly slow now, I need to get it work first.. so I * don't care performance at this moment. **/ { unsigned char * dst = (unsigned char *) surface->pixels; SDL_BlitSurface(dst_surface, &drect, surface, &srect); { for (i = 0; i < bitmap->rows; i++) { for (j = 0; j < bitmap->width; j++) { unsigned int da, dr, dg, db; unsigned int ma, mr, mg, mb; /* ARGB mask */ ma = src[j * 4 + 0]; mr = src[j * 4 + 1]; mg = src[j * 4 + 2]; mb = src[j * 4 + 3]; /* dst color */ dr = dst[j * 4 + 3]; dg = dst[j * 4 + 2]; db = dst[j * 4 + 1]; da = dst[j * 4 + 0]; dst[j * 4 + 3] = sdl_freetype_component_alpha_over (r, a, mr, ma, dr); dst[j * 4 + 2] = sdl_freetype_component_alpha_over (g, a, mg, ma, dg); dst[j * 4 + 1] = sdl_freetype_component_alpha_over (b, a, mb, ma, db); dst[j * 4 + 0] = sdl_freetype_component_alpha_over (a, a, ma, ma, da); } src += bitmap->pitch; dst += surface->pitch; } } /* XXX: the dst alpha will be incorrect? */ SDL_SetAlpha (surface, 0, 255); } break; case FT_PIXEL_MODE_LCD_V: src = bitmap->buffer; { unsigned char * dst = (unsigned char *) surface->pixels; SDL_BlitSurface(dst_surface, &drect, surface, &srect); { for (i = 0; i < bitmap->rows; i++) { for (j = 0; j < bitmap->width; j++) { unsigned int da, dr, dg, db; unsigned int ma, mr, mg, mb; /* ARGB mask */ ma = src[j * 4 + 3]; mr = src[j * 4 + 2]; mg = src[j * 4 + 1]; mb = src[j * 4 + 0]; /* dst color */ dr = dst[j * 4 + 3]; dg = dst[j * 4 + 2]; db = dst[j * 4 + 1]; da = dst[j * 4 + 0]; dst[j * 4 + 3] = sdl_freetype_component_alpha_over (r, a, mr, ma, dr); dst[j * 4 + 2] = sdl_freetype_component_alpha_over (g, a, mg, ma, dg); dst[j * 4 + 1] = sdl_freetype_component_alpha_over (b, a, mb, ma, db); dst[j * 4 + 0] = sdl_freetype_component_alpha_over (a, a, ma, ma, da); } src += bitmap->pitch; dst += surface->pitch; } } /* XXX: the dst alpha will be incorrect? */ SDL_SetAlpha (surface, 0, 255); } break; } SDL_BlitSurface(surface, &srect, dst_surface, &drect); SDL_FreeSurface (surface); return SDL_FREETYPE_ERR_OK; } #else static sdl_freetype_error_t sdl_freetype_glyph_composite (sdl_freetype_font_t * font, void * dst_surface, unsigned int r, unsigned int g, unsigned int b, unsigned int a, int x, int y, const FT_Bitmap * bitmap, int x_offset, int y_offset) { return SDL_FREETYPE_ERR_NOT_IMPLEMENTED; } #endif static sdl_freetype_error_t sdl_glyph_render (sdl_freetype_font_t * font, void * dst, unsigned int r, unsigned int g, unsigned int b, unsigned int a, int x, int y, FT_UInt index, const FT_Bitmap * glyph, int x_offset, int y_offset) { return sdl_freetype_glyph_composite (font, dst, r, g, b, a, x, y, glyph, x_offset, y_offset); } sdl_freetype_glyph_render_t sdl_freetype_default_glyph_render = { SDL_FT_RENDER_CAPS_NONE, NULL, NULL, sdl_glyph_render, NULL };