trunk/src/osd/modules/font/font_osx.c
| r0 | r243011 | |
| 1 | /* |
| 2 | * font_sdl.c |
| 3 | * |
| 4 | */ |
| 5 | |
| 6 | #include <Carbon/Carbon.h> |
| 7 | |
| 8 | #include "osdepend.h" |
| 9 | |
| 10 | #include "astring.h" |
| 11 | #include "corealloc.h" |
| 12 | #include "fileio.h" |
| 13 | |
| 14 | #define POINT_SIZE 144.0 |
| 15 | #define EXTRA_HEIGHT 1.0 |
| 16 | #define EXTRA_WIDTH 1.15 |
| 17 | |
| 18 | //------------------------------------------------- |
| 19 | // font_open - attempt to "open" a handle to the |
| 20 | // font with the given name |
| 21 | //------------------------------------------------- |
| 22 | |
| 23 | class osd_font_osx : public osd_font |
| 24 | { |
| 25 | public: |
| 26 | virtual ~osd_font_osx() {}; |
| 27 | |
| 28 | virtual bool open(const char *font_path, const char *name, int &height); |
| 29 | virtual void close(); |
| 30 | virtual bool get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs); |
| 31 | private: |
| 32 | CTFontRef m_font; |
| 33 | }; |
| 34 | |
| 35 | osd_font *osd_font_alloc() |
| 36 | { |
| 37 | return global_alloc(osd_font_osx); |
| 38 | } |
| 39 | |
| 40 | bool osd_font_osx::open(const char *font_path, const char *_name, int &height) |
| 41 | { |
| 42 | CFStringRef font_name = NULL; |
| 43 | CTFontRef ct_font = NULL; |
| 44 | CTFontDescriptorRef font_descriptor; |
| 45 | CGAffineTransform affine_transform = CGAffineTransformIdentity; |
| 46 | |
| 47 | m_font = NULL; |
| 48 | astring name(_name); |
| 49 | printf("FONT NAME %s\n", _name); |
| 50 | #if 0 |
| 51 | if (name == "default") |
| 52 | { |
| 53 | name = "LucidaGrande"; |
| 54 | } |
| 55 | #endif |
| 56 | /* handle bdf fonts in the core */ |
| 57 | if (name.len() > 4) |
| 58 | if (name.makeupper().substr(name.len()-4,4) == ".BDF" ) |
| 59 | return false; |
| 60 | |
| 61 | font_name = CFStringCreateWithCString( NULL, name.cstr(), kCFStringEncodingUTF8 ); |
| 62 | if( font_name != NULL ) |
| 63 | { |
| 64 | font_descriptor = CTFontDescriptorCreateWithNameAndSize( font_name, 0.0); //POINT_SIZE ); |
| 65 | |
| 66 | if( font_descriptor != NULL ) |
| 67 | { |
| 68 | ct_font = CTFontCreateWithFontDescriptor( font_descriptor, POINT_SIZE, &affine_transform ); |
| 69 | |
| 70 | CFRelease( font_descriptor ); |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | CFRelease( font_name ); |
| 75 | |
| 76 | if (!ct_font) |
| 77 | { |
| 78 | osd_printf_verbose("Couldn't find/open font %s, using MAME default\n", name.cstr()); |
| 79 | return false; |
| 80 | } |
| 81 | |
| 82 | CFStringRef real_name = CTFontCopyPostScriptName( ct_font ); |
| 83 | char real_name_c_string[255]; |
| 84 | CFStringGetCString ( real_name, real_name_c_string, 255, kCFStringEncodingUTF8 ); |
| 85 | osd_printf_verbose("Matching font: %s\n", real_name_c_string); |
| 86 | CFRelease( real_name ); |
| 87 | |
| 88 | CGFloat line_height = 0.0; |
| 89 | line_height += CTFontGetAscent(ct_font); |
| 90 | line_height += CTFontGetDescent(ct_font); |
| 91 | line_height += CTFontGetLeading(ct_font); |
| 92 | height = ceilf(line_height * EXTRA_HEIGHT); |
| 93 | |
| 94 | m_font = ct_font; |
| 95 | return true; |
| 96 | } |
| 97 | |
| 98 | //------------------------------------------------- |
| 99 | // font_close - release resources associated with |
| 100 | // a given OSD font |
| 101 | //------------------------------------------------- |
| 102 | |
| 103 | void osd_font_osx::close() |
| 104 | { |
| 105 | if( m_font != NULL ) |
| 106 | { |
| 107 | CFRelease( m_font ); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | //------------------------------------------------- |
| 112 | // font_get_bitmap - allocate and populate a |
| 113 | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 114 | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 115 | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 116 | // pixel of a black & white font |
| 117 | //------------------------------------------------- |
| 118 | |
| 119 | bool osd_font_osx::get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 120 | { |
| 121 | UniChar uni_char; |
| 122 | CGGlyph glyph; |
| 123 | CTFontRef ct_font = m_font; |
| 124 | const CFIndex count = 1; |
| 125 | CGRect bounding_rect, success_rect; |
| 126 | CGContextRef context_ref; |
| 127 | |
| 128 | if( chnum == ' ' ) |
| 129 | { |
| 130 | uni_char = 'n'; |
| 131 | CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); |
| 132 | success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); |
| 133 | uni_char = chnum; |
| 134 | CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); |
| 135 | } |
| 136 | else |
| 137 | { |
| 138 | uni_char = chnum; |
| 139 | CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); |
| 140 | success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); |
| 141 | } |
| 142 | |
| 143 | if( CGRectEqualToRect( success_rect, CGRectNull ) == false ) |
| 144 | { |
| 145 | size_t bitmap_width; |
| 146 | size_t bitmap_height; |
| 147 | |
| 148 | bitmap_width = ceilf(bounding_rect.size.width * EXTRA_WIDTH); |
| 149 | bitmap_width = bitmap_width == 0 ? 1 : bitmap_width; |
| 150 | |
| 151 | bitmap_height = ceilf( (CTFontGetAscent(ct_font) + CTFontGetDescent(ct_font) + CTFontGetLeading(ct_font)) * EXTRA_HEIGHT); |
| 152 | |
| 153 | xoffs = yoffs = 0; |
| 154 | width = bitmap_width; |
| 155 | |
| 156 | size_t bits_per_component; |
| 157 | CGColorSpaceRef color_space; |
| 158 | CGBitmapInfo bitmap_info = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; |
| 159 | |
| 160 | color_space = CGColorSpaceCreateDeviceRGB(); |
| 161 | bits_per_component = 8; |
| 162 | |
| 163 | bitmap.allocate(bitmap_width, bitmap_height); |
| 164 | |
| 165 | context_ref = CGBitmapContextCreate( bitmap.raw_pixptr(0), bitmap_width, bitmap_height, bits_per_component, bitmap.rowpixels()*4, color_space, bitmap_info ); |
| 166 | |
| 167 | if( context_ref != NULL ) |
| 168 | { |
| 169 | CGFontRef font_ref; |
| 170 | font_ref = CTFontCopyGraphicsFont( ct_font, NULL ); |
| 171 | CGContextSetTextPosition(context_ref, -bounding_rect.origin.x*EXTRA_WIDTH, CTFontGetDescent(ct_font)+CTFontGetLeading(ct_font) ); |
| 172 | CGContextSetRGBFillColor(context_ref, 1.0, 1.0, 1.0, 1.0); |
| 173 | CGContextSetFont( context_ref, font_ref ); |
| 174 | CGContextSetFontSize( context_ref, POINT_SIZE ); |
| 175 | CGContextShowGlyphs( context_ref, &glyph, count ); |
| 176 | CGFontRelease( font_ref ); |
| 177 | CGContextRelease( context_ref ); |
| 178 | } |
| 179 | |
| 180 | CGColorSpaceRelease( color_space ); |
| 181 | } |
| 182 | |
| 183 | return bitmap.valid(); |
| 184 | } |
| 185 | |
trunk/src/osd/modules/font/font_unix.c
| r0 | r243011 | |
| 1 | /* |
| 2 | * font_sdl.c |
| 3 | * |
| 4 | */ |
| 5 | |
| 6 | #if (SDLMAME_SDL2) |
| 7 | #include <SDL2/SDL_ttf.h> |
| 8 | #else |
| 9 | #include <SDL/SDL_ttf.h> |
| 10 | #endif |
| 11 | #ifndef SDLMAME_HAIKU |
| 12 | #include <fontconfig/fontconfig.h> |
| 13 | #endif |
| 14 | |
| 15 | #include "osdepend.h" |
| 16 | |
| 17 | #include "astring.h" |
| 18 | #include "corealloc.h" |
| 19 | #include "fileio.h" |
| 20 | |
| 21 | #define POINT_SIZE 144.0 |
| 22 | |
| 23 | //------------------------------------------------- |
| 24 | // font_open - attempt to "open" a handle to the |
| 25 | // font with the given name |
| 26 | //------------------------------------------------- |
| 27 | |
| 28 | class osd_font_unix : public osd_font |
| 29 | { |
| 30 | public: |
| 31 | virtual ~osd_font_unix() {}; |
| 32 | |
| 33 | virtual bool open(const char *font_path, const char *name, int &height); |
| 34 | virtual void close(); |
| 35 | virtual bool get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs); |
| 36 | private: |
| 37 | #ifndef SDLMAME_HAIKU |
| 38 | TTF_Font *search_font_config(astring name, bool bold, bool italic, bool underline, bool &bakedstyles); |
| 39 | #endif |
| 40 | bool BDF_Check_Magic(astring name); |
| 41 | TTF_Font * TTF_OpenFont_Magic(astring name, int fsize); |
| 42 | TTF_Font *m_font; |
| 43 | }; |
| 44 | |
| 45 | osd_font *osd_font_alloc() |
| 46 | { |
| 47 | return global_alloc(osd_font_unix); |
| 48 | } |
| 49 | |
| 50 | bool osd_font_unix::open(const char *font_path, const char *_name, int &height) |
| 51 | { |
| 52 | TTF_Font *font = (TTF_Font *)NULL; |
| 53 | bool bakedstyles = false; |
| 54 | int style = 0; |
| 55 | |
| 56 | // accept qualifiers from the name |
| 57 | astring name(_name); |
| 58 | |
| 59 | if (name == "default") |
| 60 | { |
| 61 | name = "Liberation Sans"; |
| 62 | } |
| 63 | |
| 64 | bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); |
| 65 | bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); |
| 66 | bool underline = (name.replace(0, "[U]", "") + name.replace(0, "[u]", "") > 0); |
| 67 | bool strike = (name.replace(0, "[S]", "") + name.replace(0, "[s]", "") > 0); |
| 68 | |
| 69 | // first up, try it as a filename |
| 70 | font = TTF_OpenFont_Magic(name, POINT_SIZE); |
| 71 | |
| 72 | // if no success, try the font path |
| 73 | |
| 74 | if (!font) |
| 75 | { |
| 76 | osd_printf_verbose("Searching font %s in -%s\n", name.cstr(), OPTION_FONTPATH); |
| 77 | //emu_file file(options().font_path(), OPEN_FLAG_READ); |
| 78 | emu_file file(font_path, OPEN_FLAG_READ); |
| 79 | if (file.open(name) == FILERR_NONE) |
| 80 | { |
| 81 | astring full_name = file.fullpath(); |
| 82 | font = TTF_OpenFont_Magic(full_name, POINT_SIZE); |
| 83 | if (font) |
| 84 | osd_printf_verbose("Found font %s\n", full_name.cstr()); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | // if that didn't work, crank up the FontConfig database |
| 89 | #ifndef SDLMAME_HAIKU |
| 90 | if (!font) |
| 91 | { |
| 92 | font = search_font_config(name, bold, italic, underline, bakedstyles); |
| 93 | } |
| 94 | #endif |
| 95 | |
| 96 | if (!font) |
| 97 | { |
| 98 | if (!BDF_Check_Magic(name)) |
| 99 | { |
| 100 | osd_printf_verbose("font %s is not TrueType or BDF, using MAME default\n", name.cstr()); |
| 101 | } |
| 102 | return NULL; |
| 103 | } |
| 104 | |
| 105 | // apply styles |
| 106 | if (!bakedstyles) |
| 107 | { |
| 108 | style |= bold ? TTF_STYLE_BOLD : 0; |
| 109 | style |= italic ? TTF_STYLE_ITALIC : 0; |
| 110 | } |
| 111 | style |= underline ? TTF_STYLE_UNDERLINE : 0; |
| 112 | // SDL_ttf 2.0.9 and earlier does not define TTF_STYLE_STRIKETHROUGH |
| 113 | #if SDL_VERSIONNUM(TTF_MAJOR_VERSION, TTF_MINOR_VERSION, TTF_PATCHLEVEL) > SDL_VERSIONNUM(2,0,9) |
| 114 | style |= strike ? TTF_STYLE_STRIKETHROUGH : 0; |
| 115 | #else |
| 116 | if (strike) |
| 117 | osd_printf_warning("Ignoring strikethrough for SDL_TTF older than 2.0.10\n"); |
| 118 | #endif // PATCHLEVEL |
| 119 | TTF_SetFontStyle(font, style); |
| 120 | |
| 121 | height = TTF_FontLineSkip(font); |
| 122 | |
| 123 | m_font = font; |
| 124 | return true; |
| 125 | } |
| 126 | |
| 127 | //------------------------------------------------- |
| 128 | // font_close - release resources associated with |
| 129 | // a given OSD font |
| 130 | //------------------------------------------------- |
| 131 | |
| 132 | void osd_font_unix::close() |
| 133 | { |
| 134 | TTF_CloseFont(this->m_font); |
| 135 | } |
| 136 | |
| 137 | //------------------------------------------------- |
| 138 | // font_get_bitmap - allocate and populate a |
| 139 | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 140 | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 141 | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 142 | // pixel of a black & white font |
| 143 | //------------------------------------------------- |
| 144 | |
| 145 | bool osd_font_unix::get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 146 | { |
| 147 | TTF_Font *ttffont; |
| 148 | SDL_Surface *drawsurf; |
| 149 | SDL_Color fcol = { 0xff, 0xff, 0xff }; |
| 150 | UINT16 ustr[16]; |
| 151 | |
| 152 | ttffont = m_font; |
| 153 | |
| 154 | memset(ustr,0,sizeof(ustr)); |
| 155 | ustr[0] = (UINT16)chnum; |
| 156 | drawsurf = TTF_RenderUNICODE_Solid(ttffont, ustr, fcol); |
| 157 | |
| 158 | // was nothing returned? |
| 159 | if (drawsurf) |
| 160 | { |
| 161 | // allocate a MAME destination bitmap |
| 162 | bitmap.allocate(drawsurf->w, drawsurf->h); |
| 163 | |
| 164 | // copy the rendered character image into it |
| 165 | for (int y = 0; y < bitmap.height(); y++) |
| 166 | { |
| 167 | UINT32 *dstrow = &bitmap.pix32(y); |
| 168 | UINT8 *srcrow = (UINT8 *)drawsurf->pixels; |
| 169 | |
| 170 | srcrow += (y * drawsurf->pitch); |
| 171 | |
| 172 | for (int x = 0; x < drawsurf->w; x++) |
| 173 | { |
| 174 | dstrow[x] = srcrow[x] ? rgb_t(0xff,0xff,0xff,0xff) : rgb_t(0x00,0xff,0xff,0xff); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | // what are these? |
| 179 | xoffs = yoffs = 0; |
| 180 | width = drawsurf->w; |
| 181 | |
| 182 | SDL_FreeSurface(drawsurf); |
| 183 | } |
| 184 | |
| 185 | return bitmap.valid(); |
| 186 | } |
| 187 | |
| 188 | TTF_Font * osd_font_unix::TTF_OpenFont_Magic(astring name, int fsize) |
| 189 | { |
| 190 | emu_file file(OPEN_FLAG_READ); |
| 191 | if (file.open(name) == FILERR_NONE) |
| 192 | { |
| 193 | unsigned char buffer[5] = { 0xff, 0xff, 0xff, 0xff, 0xff }; |
| 194 | unsigned char magic[5] = { 0x00, 0x01, 0x00, 0x00, 0x00 }; |
| 195 | file.read(buffer,5); |
| 196 | if (memcmp(buffer, magic, 5)) |
| 197 | return NULL; |
| 198 | } |
| 199 | return TTF_OpenFont(name.cstr(), POINT_SIZE); |
| 200 | } |
| 201 | |
| 202 | bool osd_font_unix::BDF_Check_Magic(astring name) |
| 203 | { |
| 204 | emu_file file(OPEN_FLAG_READ); |
| 205 | if (file.open(name) == FILERR_NONE) |
| 206 | { |
| 207 | unsigned char buffer[9]; |
| 208 | unsigned char magic[9] = { 'S', 'T', 'A', 'R', 'T', 'F', 'O', 'N', 'T' }; |
| 209 | file.read(buffer, 9); |
| 210 | file.close(); |
| 211 | if (!memcmp(buffer, magic, 9)) |
| 212 | return true; |
| 213 | } |
| 214 | |
| 215 | return false; |
| 216 | } |
| 217 | |
| 218 | #ifndef SDLMAME_HAIKU |
| 219 | TTF_Font *osd_font_unix::search_font_config(astring name, bool bold, bool italic, bool underline, bool &bakedstyles) |
| 220 | { |
| 221 | TTF_Font *font = (TTF_Font *)NULL; |
| 222 | FcConfig *config; |
| 223 | FcPattern *pat; |
| 224 | FcObjectSet *os; |
| 225 | FcFontSet *fontset; |
| 226 | FcValue val; |
| 227 | |
| 228 | config = FcConfigGetCurrent(); |
| 229 | pat = FcPatternCreate(); |
| 230 | os = FcObjectSetCreate(); |
| 231 | FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *)name.cstr()); |
| 232 | |
| 233 | // try and get a font with the requested styles baked-in |
| 234 | if (bold) |
| 235 | { |
| 236 | if (italic) |
| 237 | { |
| 238 | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Bold Italic"); |
| 239 | } |
| 240 | else |
| 241 | { |
| 242 | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Bold"); |
| 243 | } |
| 244 | } |
| 245 | else if (italic) |
| 246 | { |
| 247 | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Italic"); |
| 248 | } |
| 249 | else |
| 250 | { |
| 251 | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Regular"); |
| 252 | } |
| 253 | |
| 254 | FcPatternAddString(pat, FC_FONTFORMAT, (const FcChar8 *)"TrueType"); |
| 255 | |
| 256 | FcObjectSetAdd(os, FC_FILE); |
| 257 | fontset = FcFontList(config, pat, os); |
| 258 | |
| 259 | for (int i = 0; i < fontset->nfont; i++) |
| 260 | { |
| 261 | if (FcPatternGet(fontset->fonts[i], FC_FILE, 0, &val) != FcResultMatch) |
| 262 | { |
| 263 | continue; |
| 264 | } |
| 265 | |
| 266 | if (val.type != FcTypeString) |
| 267 | { |
| 268 | continue; |
| 269 | } |
| 270 | |
| 271 | osd_printf_verbose("Matching font: %s\n", val.u.s); |
| 272 | { |
| 273 | astring match_name((const char*)val.u.s); |
| 274 | font = TTF_OpenFont_Magic(match_name, POINT_SIZE); |
| 275 | } |
| 276 | |
| 277 | if (font) |
| 278 | { |
| 279 | bakedstyles = true; |
| 280 | break; |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | // didn't get a font above? try again with no baked-in styles |
| 285 | if (!font) |
| 286 | { |
| 287 | FcPatternDestroy(pat); |
| 288 | FcFontSetDestroy(fontset); |
| 289 | |
| 290 | pat = FcPatternCreate(); |
| 291 | FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *)name.cstr()); |
| 292 | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Regular"); |
| 293 | FcPatternAddString(pat, FC_FONTFORMAT, (const FcChar8 *)"TrueType"); |
| 294 | fontset = FcFontList(config, pat, os); |
| 295 | |
| 296 | for (int i = 0; i < fontset->nfont; i++) |
| 297 | { |
| 298 | if (FcPatternGet(fontset->fonts[i], FC_FILE, 0, &val) != FcResultMatch) |
| 299 | { |
| 300 | continue; |
| 301 | } |
| 302 | |
| 303 | if (val.type != FcTypeString) |
| 304 | { |
| 305 | continue; |
| 306 | } |
| 307 | |
| 308 | osd_printf_verbose("Matching unstyled font: %s\n", val.u.s); |
| 309 | { |
| 310 | astring match_name((const char*)val.u.s); |
| 311 | font = TTF_OpenFont_Magic(match_name, POINT_SIZE); |
| 312 | } |
| 313 | |
| 314 | if (font) |
| 315 | { |
| 316 | break; |
| 317 | } |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | FcPatternDestroy(pat); |
| 322 | FcObjectSetDestroy(os); |
| 323 | FcFontSetDestroy(fontset); |
| 324 | return font; |
| 325 | } |
| 326 | #endif |
trunk/src/osd/modules/font/font_windows.c
| r0 | r243011 | |
| 1 | /* |
| 2 | * font_sdl.c |
| 3 | * |
| 4 | */ |
| 5 | |
| 6 | #define WIN32_LEAN_AND_MEAN |
| 7 | #include <windows.h> |
| 8 | #include <commctrl.h> |
| 9 | #include <mmsystem.h> |
| 10 | #include <tchar.h> |
| 11 | #include <io.h> |
| 12 | |
| 13 | #include "osdepend.h" |
| 14 | |
| 15 | #include "strconv.h" |
| 16 | #include "astring.h" |
| 17 | #include "corealloc.h" |
| 18 | #include "fileio.h" |
| 19 | |
| 20 | //#define POINT_SIZE 144.0 |
| 21 | #define DEFAULT_FONT_HEIGHT (200) |
| 22 | |
| 23 | #if 0 |
| 24 | //============================================================ |
| 25 | // wstring_from_utf8 |
| 26 | //============================================================ |
| 27 | |
| 28 | // FIXME: defined in multiple locations ... FIXME |
| 29 | |
| 30 | WCHAR *wstring_from_utf8(const char *utf8string) |
| 31 | { |
| 32 | int char_count; |
| 33 | WCHAR *result; |
| 34 | |
| 35 | // convert MAME string (UTF-8) to UTF-16 |
| 36 | char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, NULL, 0); |
| 37 | result = (WCHAR *)osd_malloc_array(char_count * sizeof(*result)); |
| 38 | if (result != NULL) |
| 39 | MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count); |
| 40 | |
| 41 | return result; |
| 42 | } |
| 43 | |
| 44 | |
| 45 | //============================================================ |
| 46 | // utf8_from_wstring |
| 47 | //============================================================ |
| 48 | |
| 49 | char *utf8_from_wstring(const WCHAR *wstring) |
| 50 | { |
| 51 | int char_count; |
| 52 | char *result; |
| 53 | |
| 54 | // convert UTF-16 to MAME string (UTF-8) |
| 55 | char_count = WideCharToMultiByte(CP_UTF8, 0, wstring, -1, NULL, 0, NULL, NULL); |
| 56 | result = (char *)osd_malloc_array(char_count * sizeof(*result)); |
| 57 | if (result != NULL) |
| 58 | WideCharToMultiByte(CP_UTF8, 0, wstring, -1, result, char_count, NULL, NULL); |
| 59 | |
| 60 | return result; |
| 61 | } |
| 62 | #endif |
| 63 | |
| 64 | //------------------------------------------------- |
| 65 | // font_open - attempt to "open" a handle to the |
| 66 | // font with the given name |
| 67 | //------------------------------------------------- |
| 68 | |
| 69 | class osd_font_windows : public osd_font |
| 70 | { |
| 71 | public: |
| 72 | virtual ~osd_font_windows() {}; |
| 73 | |
| 74 | virtual bool open(const char *font_path, const char *name, int &height); |
| 75 | virtual void close(); |
| 76 | virtual bool get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs); |
| 77 | private: |
| 78 | HGDIOBJ m_font; |
| 79 | }; |
| 80 | |
| 81 | osd_font *osd_font_alloc() |
| 82 | { |
| 83 | return global_alloc(osd_font_windows); |
| 84 | } |
| 85 | |
| 86 | bool osd_font_windows::open(const char *font_path, const char *_name, int &height) |
| 87 | { |
| 88 | // accept qualifiers from the name |
| 89 | astring name(_name); |
| 90 | if (name == "default") name = "Tahoma"; |
| 91 | bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); |
| 92 | bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); |
| 93 | |
| 94 | // build a basic LOGFONT description of what we want |
| 95 | LOGFONT logfont; |
| 96 | logfont.lfHeight = DEFAULT_FONT_HEIGHT; |
| 97 | logfont.lfWidth = 0; |
| 98 | logfont.lfEscapement = 0; |
| 99 | logfont.lfOrientation = 0; |
| 100 | logfont.lfWeight = bold ? FW_BOLD : FW_MEDIUM; |
| 101 | logfont.lfItalic = italic; |
| 102 | logfont.lfUnderline = FALSE; |
| 103 | logfont.lfStrikeOut = FALSE; |
| 104 | logfont.lfCharSet = ANSI_CHARSET; |
| 105 | logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; |
| 106 | logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
| 107 | logfont.lfQuality = NONANTIALIASED_QUALITY; |
| 108 | logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
| 109 | |
| 110 | // copy in the face name |
| 111 | TCHAR *face = tstring_from_utf8(name); |
| 112 | _tcsncpy(logfont.lfFaceName, face, sizeof(logfont.lfFaceName) / sizeof(TCHAR)); |
| 113 | logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR)-1] = 0; |
| 114 | osd_free(face); |
| 115 | |
| 116 | // create the font |
| 117 | height = logfont.lfHeight; |
| 118 | m_font = CreateFontIndirect(&logfont); |
| 119 | if (m_font == NULL) |
| 120 | return false; |
| 121 | |
| 122 | // select it into a temp DC and get the real font name |
| 123 | HDC dummyDC = CreateCompatibleDC(NULL); |
| 124 | HGDIOBJ oldfont = SelectObject(dummyDC, m_font); |
| 125 | TCHAR realname[100]; |
| 126 | GetTextFace(dummyDC, ARRAY_LENGTH(realname), realname); |
| 127 | SelectObject(dummyDC, oldfont); |
| 128 | DeleteDC(dummyDC); |
| 129 | |
| 130 | // if it doesn't match our request, fail |
| 131 | char *utf = utf8_from_tstring(realname); |
| 132 | int result = core_stricmp(utf, name); |
| 133 | osd_free(utf); |
| 134 | |
| 135 | // if we didn't match, nuke our font and fall back |
| 136 | if (result != 0) |
| 137 | { |
| 138 | DeleteObject(m_font); |
| 139 | m_font = NULL; |
| 140 | return false; |
| 141 | } |
| 142 | return true; |
| 143 | } |
| 144 | |
| 145 | //------------------------------------------------- |
| 146 | // font_close - release resources associated with |
| 147 | // a given OSD font |
| 148 | //------------------------------------------------- |
| 149 | |
| 150 | void osd_font_windows::close() |
| 151 | { |
| 152 | // delete the font ojbect |
| 153 | if (m_font != NULL) |
| 154 | DeleteObject(m_font); |
| 155 | |
| 156 | } |
| 157 | |
| 158 | //------------------------------------------------- |
| 159 | // font_get_bitmap - allocate and populate a |
| 160 | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 161 | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 162 | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 163 | // pixel of a black & white font |
| 164 | //------------------------------------------------- |
| 165 | |
| 166 | bool osd_font_windows::get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 167 | { |
| 168 | // create a dummy DC to work with |
| 169 | HDC dummyDC = CreateCompatibleDC(NULL); |
| 170 | HGDIOBJ oldfont = SelectObject(dummyDC, m_font); |
| 171 | |
| 172 | // get the text metrics |
| 173 | TEXTMETRIC metrics = { 0 }; |
| 174 | GetTextMetrics(dummyDC, &metrics); |
| 175 | |
| 176 | // get the width of this character |
| 177 | ABC abc; |
| 178 | if (!GetCharABCWidths(dummyDC, chnum, chnum, &abc)) |
| 179 | { |
| 180 | abc.abcA = 0; |
| 181 | abc.abcC = 0; |
| 182 | GetCharWidth32(dummyDC, chnum, chnum, reinterpret_cast<LPINT>(&abc.abcB)); |
| 183 | } |
| 184 | width = abc.abcA + abc.abcB + abc.abcC; |
| 185 | |
| 186 | // determine desired bitmap size |
| 187 | int bmwidth = (50 + abc.abcA + abc.abcB + abc.abcC + 50 + 31) & ~31; |
| 188 | int bmheight = 50 + metrics.tmHeight + 50; |
| 189 | |
| 190 | // describe the bitmap we want |
| 191 | BYTE bitmapinfodata[sizeof(BITMAPINFOHEADER)+2 * sizeof(RGBQUAD)] = { 0 }; |
| 192 | BITMAPINFO &info = *reinterpret_cast<BITMAPINFO *>(bitmapinfodata); |
| 193 | info.bmiHeader.biSize = sizeof(info.bmiHeader); |
| 194 | info.bmiHeader.biWidth = bmwidth; |
| 195 | info.bmiHeader.biHeight = -bmheight; |
| 196 | info.bmiHeader.biPlanes = 1; |
| 197 | info.bmiHeader.biBitCount = 1; |
| 198 | info.bmiHeader.biCompression = BI_RGB; |
| 199 | info.bmiHeader.biSizeImage = 0; |
| 200 | info.bmiHeader.biXPelsPerMeter = GetDeviceCaps(dummyDC, HORZRES) / GetDeviceCaps(dummyDC, HORZSIZE); |
| 201 | info.bmiHeader.biYPelsPerMeter = GetDeviceCaps(dummyDC, VERTRES) / GetDeviceCaps(dummyDC, VERTSIZE); |
| 202 | info.bmiHeader.biClrUsed = 0; |
| 203 | info.bmiHeader.biClrImportant = 0; |
| 204 | RGBQUAD col1 = info.bmiColors[0]; |
| 205 | RGBQUAD col2 = info.bmiColors[1]; |
| 206 | col1.rgbBlue = col1.rgbGreen = col1.rgbRed = 0x00; |
| 207 | col2.rgbBlue = col2.rgbGreen = col2.rgbRed = 0xff; |
| 208 | |
| 209 | // create a DIB to render to |
| 210 | BYTE *bits; |
| 211 | HBITMAP dib = CreateDIBSection(dummyDC, &info, DIB_RGB_COLORS, reinterpret_cast<VOID **>(&bits), NULL, 0); |
| 212 | HGDIOBJ oldbitmap = SelectObject(dummyDC, dib); |
| 213 | |
| 214 | // clear the bitmap |
| 215 | int rowbytes = bmwidth / 8; |
| 216 | memset(bits, 0, rowbytes * bmheight); |
| 217 | |
| 218 | // now draw the character |
| 219 | WCHAR tempchar = chnum; |
| 220 | SetTextColor(dummyDC, RGB(0xff, 0xff, 0xff)); |
| 221 | SetBkColor(dummyDC, RGB(0x00, 0x00, 0x00)); |
| 222 | ExtTextOutW(dummyDC, 50 + abc.abcA, 50, ETO_OPAQUE, NULL, &tempchar, 1, NULL); |
| 223 | |
| 224 | // characters are expected to be full-height |
| 225 | rectangle actbounds; |
| 226 | actbounds.min_y = 50; |
| 227 | actbounds.max_y = 50 + metrics.tmHeight - 1; |
| 228 | |
| 229 | // determine the actual left of the character |
| 230 | for (actbounds.min_x = 0; actbounds.min_x < rowbytes; actbounds.min_x++) |
| 231 | { |
| 232 | BYTE *offs = bits + actbounds.min_x; |
| 233 | UINT8 summary = 0; |
| 234 | for (int y = 0; y < bmheight; y++) |
| 235 | summary |= offs[y * rowbytes]; |
| 236 | if (summary != 0) |
| 237 | { |
| 238 | actbounds.min_x *= 8; |
| 239 | if (!(summary & 0x80)) actbounds.min_x++; |
| 240 | if (!(summary & 0xc0)) actbounds.min_x++; |
| 241 | if (!(summary & 0xe0)) actbounds.min_x++; |
| 242 | if (!(summary & 0xf0)) actbounds.min_x++; |
| 243 | if (!(summary & 0xf8)) actbounds.min_x++; |
| 244 | if (!(summary & 0xfc)) actbounds.min_x++; |
| 245 | if (!(summary & 0xfe)) actbounds.min_x++; |
| 246 | break; |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | // determine the actual right of the character |
| 251 | for (actbounds.max_x = rowbytes - 1; actbounds.max_x >= 0; actbounds.max_x--) |
| 252 | { |
| 253 | BYTE *offs = bits + actbounds.max_x; |
| 254 | UINT8 summary = 0; |
| 255 | for (int y = 0; y < bmheight; y++) |
| 256 | summary |= offs[y * rowbytes]; |
| 257 | if (summary != 0) |
| 258 | { |
| 259 | actbounds.max_x *= 8; |
| 260 | if (summary & 0x7f) actbounds.max_x++; |
| 261 | if (summary & 0x3f) actbounds.max_x++; |
| 262 | if (summary & 0x1f) actbounds.max_x++; |
| 263 | if (summary & 0x0f) actbounds.max_x++; |
| 264 | if (summary & 0x07) actbounds.max_x++; |
| 265 | if (summary & 0x03) actbounds.max_x++; |
| 266 | if (summary & 0x01) actbounds.max_x++; |
| 267 | break; |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | // allocate a new bitmap |
| 272 | if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y) |
| 273 | { |
| 274 | bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y); |
| 275 | |
| 276 | // copy the bits into it |
| 277 | for (int y = 0; y < bitmap.height(); y++) |
| 278 | { |
| 279 | UINT32 *dstrow = &bitmap.pix32(y); |
| 280 | UINT8 *srcrow = &bits[(y + actbounds.min_y) * rowbytes]; |
| 281 | for (int x = 0; x < bitmap.width(); x++) |
| 282 | { |
| 283 | int effx = x + actbounds.min_x; |
| 284 | dstrow[x] = ((srcrow[effx / 8] << (effx % 8)) & 0x80) ? rgb_t(0xff, 0xff, 0xff, 0xff) : rgb_t(0x00, 0xff, 0xff, 0xff); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | // set the final offset values |
| 289 | xoffs = actbounds.min_x - (50 + abc.abcA); |
| 290 | yoffs = actbounds.max_y - (50 + metrics.tmAscent); |
| 291 | } |
| 292 | |
| 293 | // de-select the font and release the DC |
| 294 | SelectObject(dummyDC, oldbitmap); |
| 295 | DeleteObject(dib); |
| 296 | SelectObject(dummyDC, oldfont); |
| 297 | DeleteDC(dummyDC); |
| 298 | return bitmap.valid(); |
| 299 | } |
| 300 | |
trunk/src/osd/sdl/sdlmain.c
| r243010 | r243011 | |
| 85 | 85 | |
| 86 | 86 | #include "watchdog.h" |
| 87 | 87 | |
| 88 | | #define DEFAULT_FONT_HEIGHT (200) |
| 89 | | |
| 90 | 88 | //============================================================ |
| 91 | 89 | // OPTIONS |
| 92 | 90 | //============================================================ |
| r243010 | r243011 | |
| 303 | 301 | setvbuf(stdout, (char *) NULL, _IONBF, 0); |
| 304 | 302 | setvbuf(stderr, (char *) NULL, _IONBF, 0); |
| 305 | 303 | |
| 304 | //FIXME: move to font module |
| 306 | 305 | #ifdef SDLMAME_UNIX |
| 307 | 306 | sdl_entered_debugger = 0; |
| 308 | 307 | #if (!defined(SDLMAME_MACOSX)) && (!defined(SDLMAME_HAIKU)) && (!defined(SDLMAME_EMSCRIPTEN)) |
| r243010 | r243011 | |
| 712 | 711 | #endif |
| 713 | 712 | } |
| 714 | 713 | |
| 715 | | #if defined(SDLMAME_UNIX) && (!defined(SDLMAME_EMSCRIPTEN)) |
| 716 | | #define POINT_SIZE 144.0 |
| 717 | | |
| 718 | | #ifdef SDLMAME_MACOSX |
| 719 | | |
| 720 | | #define EXTRA_HEIGHT 1.0 |
| 721 | | #define EXTRA_WIDTH 1.15 |
| 722 | | |
| 723 | | //------------------------------------------------- |
| 724 | | // font_open - attempt to "open" a handle to the |
| 725 | | // font with the given name |
| 726 | | //------------------------------------------------- |
| 727 | | |
| 728 | | class osd_font |
| 729 | | { |
| 730 | | public: |
| 731 | | CTFontRef m_font; |
| 732 | | }; |
| 733 | | |
| 734 | | osd_font *sdl_osd_interface::font_open(const char *_name, int &height) |
| 735 | | { |
| 736 | | CFStringRef font_name = NULL; |
| 737 | | CTFontRef ct_font = NULL; |
| 738 | | CTFontDescriptorRef font_descriptor; |
| 739 | | CGAffineTransform affine_transform = CGAffineTransformIdentity; |
| 740 | | |
| 741 | | astring name(_name); |
| 742 | | |
| 743 | | if (name == "default") |
| 744 | | { |
| 745 | | name = "LucidaGrande"; |
| 746 | | } |
| 747 | | |
| 748 | | /* handle bdf fonts in the core */ |
| 749 | | if (name.len() > 4) |
| 750 | | if (name.makeupper().substr(name.len()-4,4) == ".BDF" ) |
| 751 | | return NULL; |
| 752 | | |
| 753 | | font_name = CFStringCreateWithCString( NULL, name.cstr(), kCFStringEncodingUTF8 ); |
| 754 | | |
| 755 | | if( font_name != NULL ) |
| 756 | | { |
| 757 | | font_descriptor = CTFontDescriptorCreateWithNameAndSize( font_name, POINT_SIZE ); |
| 758 | | |
| 759 | | if( font_descriptor != NULL ) |
| 760 | | { |
| 761 | | ct_font = CTFontCreateWithFontDescriptor( font_descriptor, POINT_SIZE, &affine_transform ); |
| 762 | | |
| 763 | | CFRelease( font_descriptor ); |
| 764 | | } |
| 765 | | } |
| 766 | | |
| 767 | | CFRelease( font_name ); |
| 768 | | |
| 769 | | if (!ct_font) |
| 770 | | { |
| 771 | | osd_printf_verbose("Couldn't find/open font %s, using MAME default\n", name.cstr()); |
| 772 | | return NULL; |
| 773 | | } |
| 774 | | |
| 775 | | CFStringRef real_name = CTFontCopyPostScriptName( ct_font ); |
| 776 | | char real_name_c_string[255]; |
| 777 | | CFStringGetCString ( real_name, real_name_c_string, 255, kCFStringEncodingUTF8 ); |
| 778 | | osd_printf_verbose("Matching font: %s\n", real_name_c_string); |
| 779 | | CFRelease( real_name ); |
| 780 | | |
| 781 | | CGFloat line_height = 0.0; |
| 782 | | line_height += CTFontGetAscent(ct_font); |
| 783 | | line_height += CTFontGetDescent(ct_font); |
| 784 | | line_height += CTFontGetLeading(ct_font); |
| 785 | | height = ceilf(line_height * EXTRA_HEIGHT); |
| 786 | | |
| 787 | | osd_font *ret = global_alloc(osd_font); |
| 788 | | ret->m_font = ct_font; |
| 789 | | return ret; |
| 790 | | } |
| 791 | | |
| 792 | | //------------------------------------------------- |
| 793 | | // font_close - release resources associated with |
| 794 | | // a given OSD font |
| 795 | | //------------------------------------------------- |
| 796 | | |
| 797 | | void sdl_osd_interface::font_close(osd_font *font) |
| 798 | | { |
| 799 | | CTFontRef ct_font = font->m_font; |
| 800 | | |
| 801 | | if( ct_font != NULL ) |
| 802 | | { |
| 803 | | CFRelease( ct_font ); |
| 804 | | } |
| 805 | | global_free(font); |
| 806 | | } |
| 807 | | |
| 808 | | //------------------------------------------------- |
| 809 | | // font_get_bitmap - allocate and populate a |
| 810 | | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 811 | | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 812 | | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 813 | | // pixel of a black & white font |
| 814 | | //------------------------------------------------- |
| 815 | | |
| 816 | | bool sdl_osd_interface::font_get_bitmap(osd_font *font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 817 | | { |
| 818 | | UniChar uni_char; |
| 819 | | CGGlyph glyph; |
| 820 | | CTFontRef ct_font = font->m_font; |
| 821 | | const CFIndex count = 1; |
| 822 | | CGRect bounding_rect, success_rect; |
| 823 | | CGContextRef context_ref; |
| 824 | | |
| 825 | | if( chnum == ' ' ) |
| 826 | | { |
| 827 | | uni_char = 'n'; |
| 828 | | CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); |
| 829 | | success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); |
| 830 | | uni_char = chnum; |
| 831 | | CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); |
| 832 | | } |
| 833 | | else |
| 834 | | { |
| 835 | | uni_char = chnum; |
| 836 | | CTFontGetGlyphsForCharacters( ct_font, &uni_char, &glyph, count ); |
| 837 | | success_rect = CTFontGetBoundingRectsForGlyphs( ct_font, kCTFontDefaultOrientation, &glyph, &bounding_rect, count ); |
| 838 | | } |
| 839 | | |
| 840 | | if( CGRectEqualToRect( success_rect, CGRectNull ) == false ) |
| 841 | | { |
| 842 | | size_t bitmap_width; |
| 843 | | size_t bitmap_height; |
| 844 | | |
| 845 | | bitmap_width = ceilf(bounding_rect.size.width * EXTRA_WIDTH); |
| 846 | | bitmap_width = bitmap_width == 0 ? 1 : bitmap_width; |
| 847 | | |
| 848 | | bitmap_height = ceilf( (CTFontGetAscent(ct_font) + CTFontGetDescent(ct_font) + CTFontGetLeading(ct_font)) * EXTRA_HEIGHT); |
| 849 | | |
| 850 | | xoffs = yoffs = 0; |
| 851 | | width = bitmap_width; |
| 852 | | |
| 853 | | size_t bits_per_component; |
| 854 | | CGColorSpaceRef color_space; |
| 855 | | CGBitmapInfo bitmap_info = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; |
| 856 | | |
| 857 | | color_space = CGColorSpaceCreateDeviceRGB(); |
| 858 | | bits_per_component = 8; |
| 859 | | |
| 860 | | bitmap.allocate(bitmap_width, bitmap_height); |
| 861 | | |
| 862 | | context_ref = CGBitmapContextCreate( bitmap.raw_pixptr(0), bitmap_width, bitmap_height, bits_per_component, bitmap.rowpixels()*4, color_space, bitmap_info ); |
| 863 | | |
| 864 | | if( context_ref != NULL ) |
| 865 | | { |
| 866 | | CGFontRef font_ref; |
| 867 | | font_ref = CTFontCopyGraphicsFont( ct_font, NULL ); |
| 868 | | CGContextSetTextPosition(context_ref, -bounding_rect.origin.x*EXTRA_WIDTH, CTFontGetDescent(ct_font)+CTFontGetLeading(ct_font) ); |
| 869 | | CGContextSetRGBFillColor(context_ref, 1.0, 1.0, 1.0, 1.0); |
| 870 | | CGContextSetFont( context_ref, font_ref ); |
| 871 | | CGContextSetFontSize( context_ref, POINT_SIZE ); |
| 872 | | CGContextShowGlyphs( context_ref, &glyph, count ); |
| 873 | | CGFontRelease( font_ref ); |
| 874 | | CGContextRelease( context_ref ); |
| 875 | | } |
| 876 | | |
| 877 | | CGColorSpaceRelease( color_space ); |
| 878 | | } |
| 879 | | |
| 880 | | return bitmap.valid(); |
| 881 | | } |
| 882 | | #else // UNIX but not OSX |
| 883 | | |
| 884 | | static TTF_Font * TTF_OpenFont_Magic(astring name, int fsize) |
| 885 | | { |
| 886 | | emu_file file(OPEN_FLAG_READ); |
| 887 | | if (file.open(name) == FILERR_NONE) |
| 888 | | { |
| 889 | | unsigned char buffer[5] = { 0xff, 0xff, 0xff, 0xff, 0xff }; |
| 890 | | unsigned char magic[5] = { 0x00, 0x01, 0x00, 0x00, 0x00 }; |
| 891 | | file.read(buffer,5); |
| 892 | | if (memcmp(buffer, magic, 5)) |
| 893 | | return NULL; |
| 894 | | } |
| 895 | | return TTF_OpenFont(name.cstr(), POINT_SIZE); |
| 896 | | } |
| 897 | | |
| 898 | | static bool BDF_Check_Magic(astring name) |
| 899 | | { |
| 900 | | emu_file file(OPEN_FLAG_READ); |
| 901 | | if (file.open(name) == FILERR_NONE) |
| 902 | | { |
| 903 | | unsigned char buffer[9]; |
| 904 | | unsigned char magic[9] = { 'S', 'T', 'A', 'R', 'T', 'F', 'O', 'N', 'T' }; |
| 905 | | file.read(buffer, 9); |
| 906 | | file.close(); |
| 907 | | if (!memcmp(buffer, magic, 9)) |
| 908 | | return true; |
| 909 | | } |
| 910 | | |
| 911 | | return false; |
| 912 | | } |
| 913 | | |
| 914 | | #ifndef SDLMAME_HAIKU |
| 915 | | static TTF_Font *search_font_config(astring name, bool bold, bool italic, bool underline, bool &bakedstyles) |
| 916 | | { |
| 917 | | TTF_Font *font = (TTF_Font *)NULL; |
| 918 | | FcConfig *config; |
| 919 | | FcPattern *pat; |
| 920 | | FcObjectSet *os; |
| 921 | | FcFontSet *fontset; |
| 922 | | FcValue val; |
| 923 | | |
| 924 | | config = FcConfigGetCurrent(); |
| 925 | | pat = FcPatternCreate(); |
| 926 | | os = FcObjectSetCreate(); |
| 927 | | FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *)name.cstr()); |
| 928 | | |
| 929 | | // try and get a font with the requested styles baked-in |
| 930 | | if (bold) |
| 931 | | { |
| 932 | | if (italic) |
| 933 | | { |
| 934 | | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Bold Italic"); |
| 935 | | } |
| 936 | | else |
| 937 | | { |
| 938 | | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Bold"); |
| 939 | | } |
| 940 | | } |
| 941 | | else if (italic) |
| 942 | | { |
| 943 | | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Italic"); |
| 944 | | } |
| 945 | | else |
| 946 | | { |
| 947 | | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Regular"); |
| 948 | | } |
| 949 | | |
| 950 | | FcPatternAddString(pat, FC_FONTFORMAT, (const FcChar8 *)"TrueType"); |
| 951 | | |
| 952 | | FcObjectSetAdd(os, FC_FILE); |
| 953 | | fontset = FcFontList(config, pat, os); |
| 954 | | |
| 955 | | for (int i = 0; i < fontset->nfont; i++) |
| 956 | | { |
| 957 | | if (FcPatternGet(fontset->fonts[i], FC_FILE, 0, &val) != FcResultMatch) |
| 958 | | { |
| 959 | | continue; |
| 960 | | } |
| 961 | | |
| 962 | | if (val.type != FcTypeString) |
| 963 | | { |
| 964 | | continue; |
| 965 | | } |
| 966 | | |
| 967 | | osd_printf_verbose("Matching font: %s\n", val.u.s); |
| 968 | | { |
| 969 | | astring match_name((const char*)val.u.s); |
| 970 | | font = TTF_OpenFont_Magic(match_name, POINT_SIZE); |
| 971 | | } |
| 972 | | |
| 973 | | if (font) |
| 974 | | { |
| 975 | | bakedstyles = true; |
| 976 | | break; |
| 977 | | } |
| 978 | | } |
| 979 | | |
| 980 | | // didn't get a font above? try again with no baked-in styles |
| 981 | | if (!font) |
| 982 | | { |
| 983 | | FcPatternDestroy(pat); |
| 984 | | FcFontSetDestroy(fontset); |
| 985 | | |
| 986 | | pat = FcPatternCreate(); |
| 987 | | FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *)name.cstr()); |
| 988 | | FcPatternAddString(pat, FC_STYLE, (const FcChar8 *)"Regular"); |
| 989 | | FcPatternAddString(pat, FC_FONTFORMAT, (const FcChar8 *)"TrueType"); |
| 990 | | fontset = FcFontList(config, pat, os); |
| 991 | | |
| 992 | | for (int i = 0; i < fontset->nfont; i++) |
| 993 | | { |
| 994 | | if (FcPatternGet(fontset->fonts[i], FC_FILE, 0, &val) != FcResultMatch) |
| 995 | | { |
| 996 | | continue; |
| 997 | | } |
| 998 | | |
| 999 | | if (val.type != FcTypeString) |
| 1000 | | { |
| 1001 | | continue; |
| 1002 | | } |
| 1003 | | |
| 1004 | | osd_printf_verbose("Matching unstyled font: %s\n", val.u.s); |
| 1005 | | { |
| 1006 | | astring match_name((const char*)val.u.s); |
| 1007 | | font = TTF_OpenFont_Magic(match_name, POINT_SIZE); |
| 1008 | | } |
| 1009 | | |
| 1010 | | if (font) |
| 1011 | | { |
| 1012 | | break; |
| 1013 | | } |
| 1014 | | } |
| 1015 | | } |
| 1016 | | |
| 1017 | | FcPatternDestroy(pat); |
| 1018 | | FcObjectSetDestroy(os); |
| 1019 | | FcFontSetDestroy(fontset); |
| 1020 | | return font; |
| 1021 | | } |
| 1022 | | #endif |
| 1023 | | |
| 1024 | | //------------------------------------------------- |
| 1025 | | // font_open - attempt to "open" a handle to the |
| 1026 | | // font with the given name |
| 1027 | | //------------------------------------------------- |
| 1028 | | |
| 1029 | | class osd_font |
| 1030 | | { |
| 1031 | | public: |
| 1032 | | TTF_Font *m_font; |
| 1033 | | }; |
| 1034 | | |
| 1035 | | osd_font *sdl_osd_interface::font_open(const char *_name, int &height) |
| 1036 | | { |
| 1037 | | TTF_Font *font = (TTF_Font *)NULL; |
| 1038 | | bool bakedstyles = false; |
| 1039 | | int style = 0; |
| 1040 | | |
| 1041 | | // accept qualifiers from the name |
| 1042 | | astring name(_name); |
| 1043 | | |
| 1044 | | if (name == "default") |
| 1045 | | { |
| 1046 | | name = "Liberation Sans"; |
| 1047 | | } |
| 1048 | | |
| 1049 | | bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); |
| 1050 | | bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); |
| 1051 | | bool underline = (name.replace(0, "[U]", "") + name.replace(0, "[u]", "") > 0); |
| 1052 | | bool strike = (name.replace(0, "[S]", "") + name.replace(0, "[s]", "") > 0); |
| 1053 | | |
| 1054 | | // first up, try it as a filename |
| 1055 | | font = TTF_OpenFont_Magic(name, POINT_SIZE); |
| 1056 | | |
| 1057 | | // if no success, try the font path |
| 1058 | | |
| 1059 | | if (!font) |
| 1060 | | { |
| 1061 | | osd_printf_verbose("Searching font %s in -%s\n", name.cstr(), OPTION_FONTPATH); |
| 1062 | | emu_file file(options().font_path(), OPEN_FLAG_READ); |
| 1063 | | if (file.open(name) == FILERR_NONE) |
| 1064 | | { |
| 1065 | | astring full_name = file.fullpath(); |
| 1066 | | font = TTF_OpenFont_Magic(full_name, POINT_SIZE); |
| 1067 | | if (font) |
| 1068 | | osd_printf_verbose("Found font %s\n", full_name.cstr()); |
| 1069 | | } |
| 1070 | | } |
| 1071 | | |
| 1072 | | // if that didn't work, crank up the FontConfig database |
| 1073 | | #ifndef SDLMAME_HAIKU |
| 1074 | | if (!font) |
| 1075 | | { |
| 1076 | | font = search_font_config(name, bold, italic, underline, bakedstyles); |
| 1077 | | } |
| 1078 | | #endif |
| 1079 | | |
| 1080 | | if (!font) |
| 1081 | | { |
| 1082 | | if (!BDF_Check_Magic(name)) |
| 1083 | | { |
| 1084 | | osd_printf_verbose("font %s is not TrueType or BDF, using MAME default\n", name.cstr()); |
| 1085 | | } |
| 1086 | | return NULL; |
| 1087 | | } |
| 1088 | | |
| 1089 | | // apply styles |
| 1090 | | if (!bakedstyles) |
| 1091 | | { |
| 1092 | | style |= bold ? TTF_STYLE_BOLD : 0; |
| 1093 | | style |= italic ? TTF_STYLE_ITALIC : 0; |
| 1094 | | } |
| 1095 | | style |= underline ? TTF_STYLE_UNDERLINE : 0; |
| 1096 | | // SDL_ttf 2.0.9 and earlier does not define TTF_STYLE_STRIKETHROUGH |
| 1097 | | #if SDL_VERSIONNUM(TTF_MAJOR_VERSION, TTF_MINOR_VERSION, TTF_PATCHLEVEL) > SDL_VERSIONNUM(2,0,9) |
| 1098 | | style |= strike ? TTF_STYLE_STRIKETHROUGH : 0; |
| 1099 | | #else |
| 1100 | | if (strike) |
| 1101 | | osd_printf_warning("Ignoring strikethrough for SDL_TTF older than 2.0.10\n"); |
| 1102 | | #endif // PATCHLEVEL |
| 1103 | | TTF_SetFontStyle(font, style); |
| 1104 | | |
| 1105 | | height = TTF_FontLineSkip(font); |
| 1106 | | |
| 1107 | | osd_font *ret = global_alloc(osd_font); |
| 1108 | | ret->m_font = font; |
| 1109 | | return ret; |
| 1110 | | } |
| 1111 | | |
| 1112 | | //------------------------------------------------- |
| 1113 | | // font_close - release resources associated with |
| 1114 | | // a given OSD font |
| 1115 | | //------------------------------------------------- |
| 1116 | | |
| 1117 | | void sdl_osd_interface::font_close(osd_font *font) |
| 1118 | | { |
| 1119 | | TTF_CloseFont(font->m_font); |
| 1120 | | global_free(font); |
| 1121 | | } |
| 1122 | | |
| 1123 | | //------------------------------------------------- |
| 1124 | | // font_get_bitmap - allocate and populate a |
| 1125 | | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 1126 | | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 1127 | | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 1128 | | // pixel of a black & white font |
| 1129 | | //------------------------------------------------- |
| 1130 | | |
| 1131 | | bool sdl_osd_interface::font_get_bitmap(osd_font *font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 1132 | | { |
| 1133 | | TTF_Font *ttffont; |
| 1134 | | SDL_Surface *drawsurf; |
| 1135 | | SDL_Color fcol = { 0xff, 0xff, 0xff }; |
| 1136 | | UINT16 ustr[16]; |
| 1137 | | |
| 1138 | | ttffont = font->m_font; |
| 1139 | | |
| 1140 | | memset(ustr,0,sizeof(ustr)); |
| 1141 | | ustr[0] = (UINT16)chnum; |
| 1142 | | drawsurf = TTF_RenderUNICODE_Solid(ttffont, ustr, fcol); |
| 1143 | | |
| 1144 | | // was nothing returned? |
| 1145 | | if (drawsurf) |
| 1146 | | { |
| 1147 | | // allocate a MAME destination bitmap |
| 1148 | | bitmap.allocate(drawsurf->w, drawsurf->h); |
| 1149 | | |
| 1150 | | // copy the rendered character image into it |
| 1151 | | for (int y = 0; y < bitmap.height(); y++) |
| 1152 | | { |
| 1153 | | UINT32 *dstrow = &bitmap.pix32(y); |
| 1154 | | UINT8 *srcrow = (UINT8 *)drawsurf->pixels; |
| 1155 | | |
| 1156 | | srcrow += (y * drawsurf->pitch); |
| 1157 | | |
| 1158 | | for (int x = 0; x < drawsurf->w; x++) |
| 1159 | | { |
| 1160 | | dstrow[x] = srcrow[x] ? rgb_t(0xff,0xff,0xff,0xff) : rgb_t(0x00,0xff,0xff,0xff); |
| 1161 | | } |
| 1162 | | } |
| 1163 | | |
| 1164 | | // what are these? |
| 1165 | | xoffs = yoffs = 0; |
| 1166 | | width = drawsurf->w; |
| 1167 | | |
| 1168 | | SDL_FreeSurface(drawsurf); |
| 1169 | | } |
| 1170 | | |
| 1171 | | return bitmap.valid(); |
| 1172 | | } |
| 1173 | | #endif // not OSX |
| 1174 | | #else // not UNIX |
| 1175 | 714 | #ifdef SDLMAME_WIN32 |
| 1176 | 715 | |
| 1177 | 716 | //============================================================ |
| r243010 | r243011 | |
| 1211 | 750 | return result; |
| 1212 | 751 | } |
| 1213 | 752 | |
| 1214 | | osd_font *sdl_osd_interface::font_open(const char *_name, int &height) |
| 1215 | | { |
| 1216 | | // accept qualifiers from the name |
| 1217 | | astring name(_name); |
| 1218 | | if (name == "default") name = "Tahoma"; |
| 1219 | | bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); |
| 1220 | | bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); |
| 1221 | | |
| 1222 | | // build a basic LOGFONT description of what we want |
| 1223 | | LOGFONT logfont; |
| 1224 | | logfont.lfHeight = DEFAULT_FONT_HEIGHT; |
| 1225 | | logfont.lfWidth = 0; |
| 1226 | | logfont.lfEscapement = 0; |
| 1227 | | logfont.lfOrientation = 0; |
| 1228 | | logfont.lfWeight = bold ? FW_BOLD : FW_MEDIUM; |
| 1229 | | logfont.lfItalic = italic; |
| 1230 | | logfont.lfUnderline = FALSE; |
| 1231 | | logfont.lfStrikeOut = FALSE; |
| 1232 | | logfont.lfCharSet = ANSI_CHARSET; |
| 1233 | | logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; |
| 1234 | | logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
| 1235 | | logfont.lfQuality = NONANTIALIASED_QUALITY; |
| 1236 | | logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
| 1237 | | |
| 1238 | | // copy in the face name |
| 1239 | | TCHAR *face = tstring_from_utf8(name); |
| 1240 | | _tcsncpy(logfont.lfFaceName, face, sizeof(logfont.lfFaceName) / sizeof(TCHAR)); |
| 1241 | | logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR)-1] = 0; |
| 1242 | | osd_free(face); |
| 1243 | | |
| 1244 | | // create the font |
| 1245 | | height = logfont.lfHeight; |
| 1246 | | osd_font *font = reinterpret_cast<osd_font *>(CreateFontIndirect(&logfont)); |
| 1247 | | if (font == NULL) |
| 1248 | | return NULL; |
| 1249 | | |
| 1250 | | // select it into a temp DC and get the real font name |
| 1251 | | HDC dummyDC = CreateCompatibleDC(NULL); |
| 1252 | | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 1253 | | TCHAR realname[100]; |
| 1254 | | GetTextFace(dummyDC, ARRAY_LENGTH(realname), realname); |
| 1255 | | SelectObject(dummyDC, oldfont); |
| 1256 | | DeleteDC(dummyDC); |
| 1257 | | |
| 1258 | | // if it doesn't match our request, fail |
| 1259 | | char *utf = utf8_from_tstring(realname); |
| 1260 | | int result = core_stricmp(utf, name); |
| 1261 | | osd_free(utf); |
| 1262 | | |
| 1263 | | // if we didn't match, nuke our font and fall back |
| 1264 | | if (result != 0) |
| 1265 | | { |
| 1266 | | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 1267 | | font = NULL; |
| 1268 | | } |
| 1269 | | return font; |
| 1270 | | } |
| 1271 | | |
| 1272 | | |
| 1273 | | //------------------------------------------------- |
| 1274 | | // font_close - release resources associated with |
| 1275 | | // a given OSD font |
| 1276 | | //------------------------------------------------- |
| 1277 | | |
| 1278 | | void sdl_osd_interface::font_close(osd_font *font) |
| 1279 | | { |
| 1280 | | // delete the font ojbect |
| 1281 | | if (font != NULL) |
| 1282 | | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 1283 | | } |
| 1284 | | |
| 1285 | | |
| 1286 | | //------------------------------------------------- |
| 1287 | | // font_get_bitmap - allocate and populate a |
| 1288 | | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 1289 | | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 1290 | | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 1291 | | // pixel of a black & white font |
| 1292 | | //------------------------------------------------- |
| 1293 | | |
| 1294 | | bool sdl_osd_interface::font_get_bitmap(osd_font *font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 1295 | | { |
| 1296 | | // create a dummy DC to work with |
| 1297 | | HDC dummyDC = CreateCompatibleDC(NULL); |
| 1298 | | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 1299 | | |
| 1300 | | // get the text metrics |
| 1301 | | TEXTMETRIC metrics = { 0 }; |
| 1302 | | GetTextMetrics(dummyDC, &metrics); |
| 1303 | | |
| 1304 | | // get the width of this character |
| 1305 | | ABC abc; |
| 1306 | | if (!GetCharABCWidths(dummyDC, chnum, chnum, &abc)) |
| 1307 | | { |
| 1308 | | abc.abcA = 0; |
| 1309 | | abc.abcC = 0; |
| 1310 | | GetCharWidth32(dummyDC, chnum, chnum, reinterpret_cast<LPINT>(&abc.abcB)); |
| 1311 | | } |
| 1312 | | width = abc.abcA + abc.abcB + abc.abcC; |
| 1313 | | |
| 1314 | | // determine desired bitmap size |
| 1315 | | int bmwidth = (50 + abc.abcA + abc.abcB + abc.abcC + 50 + 31) & ~31; |
| 1316 | | int bmheight = 50 + metrics.tmHeight + 50; |
| 1317 | | |
| 1318 | | // describe the bitmap we want |
| 1319 | | BYTE bitmapinfodata[sizeof(BITMAPINFOHEADER)+2 * sizeof(RGBQUAD)] = { 0 }; |
| 1320 | | BITMAPINFO &info = *reinterpret_cast<BITMAPINFO *>(bitmapinfodata); |
| 1321 | | info.bmiHeader.biSize = sizeof(info.bmiHeader); |
| 1322 | | info.bmiHeader.biWidth = bmwidth; |
| 1323 | | info.bmiHeader.biHeight = -bmheight; |
| 1324 | | info.bmiHeader.biPlanes = 1; |
| 1325 | | info.bmiHeader.biBitCount = 1; |
| 1326 | | info.bmiHeader.biCompression = BI_RGB; |
| 1327 | | info.bmiHeader.biSizeImage = 0; |
| 1328 | | info.bmiHeader.biXPelsPerMeter = GetDeviceCaps(dummyDC, HORZRES) / GetDeviceCaps(dummyDC, HORZSIZE); |
| 1329 | | info.bmiHeader.biYPelsPerMeter = GetDeviceCaps(dummyDC, VERTRES) / GetDeviceCaps(dummyDC, VERTSIZE); |
| 1330 | | info.bmiHeader.biClrUsed = 0; |
| 1331 | | info.bmiHeader.biClrImportant = 0; |
| 1332 | | RGBQUAD col1 = info.bmiColors[0]; |
| 1333 | | RGBQUAD col2 = info.bmiColors[1]; |
| 1334 | | col1.rgbBlue = col1.rgbGreen = col1.rgbRed = 0x00; |
| 1335 | | col2.rgbBlue = col2.rgbGreen = col2.rgbRed = 0xff; |
| 1336 | | |
| 1337 | | // create a DIB to render to |
| 1338 | | BYTE *bits; |
| 1339 | | HBITMAP dib = CreateDIBSection(dummyDC, &info, DIB_RGB_COLORS, reinterpret_cast<VOID **>(&bits), NULL, 0); |
| 1340 | | HGDIOBJ oldbitmap = SelectObject(dummyDC, dib); |
| 1341 | | |
| 1342 | | // clear the bitmap |
| 1343 | | int rowbytes = bmwidth / 8; |
| 1344 | | memset(bits, 0, rowbytes * bmheight); |
| 1345 | | |
| 1346 | | // now draw the character |
| 1347 | | WCHAR tempchar = chnum; |
| 1348 | | SetTextColor(dummyDC, RGB(0xff, 0xff, 0xff)); |
| 1349 | | SetBkColor(dummyDC, RGB(0x00, 0x00, 0x00)); |
| 1350 | | ExtTextOutW(dummyDC, 50 + abc.abcA, 50, ETO_OPAQUE, NULL, &tempchar, 1, NULL); |
| 1351 | | |
| 1352 | | // characters are expected to be full-height |
| 1353 | | rectangle actbounds; |
| 1354 | | actbounds.min_y = 50; |
| 1355 | | actbounds.max_y = 50 + metrics.tmHeight - 1; |
| 1356 | | |
| 1357 | | // determine the actual left of the character |
| 1358 | | for (actbounds.min_x = 0; actbounds.min_x < rowbytes; actbounds.min_x++) |
| 1359 | | { |
| 1360 | | BYTE *offs = bits + actbounds.min_x; |
| 1361 | | UINT8 summary = 0; |
| 1362 | | for (int y = 0; y < bmheight; y++) |
| 1363 | | summary |= offs[y * rowbytes]; |
| 1364 | | if (summary != 0) |
| 1365 | | { |
| 1366 | | actbounds.min_x *= 8; |
| 1367 | | if (!(summary & 0x80)) actbounds.min_x++; |
| 1368 | | if (!(summary & 0xc0)) actbounds.min_x++; |
| 1369 | | if (!(summary & 0xe0)) actbounds.min_x++; |
| 1370 | | if (!(summary & 0xf0)) actbounds.min_x++; |
| 1371 | | if (!(summary & 0xf8)) actbounds.min_x++; |
| 1372 | | if (!(summary & 0xfc)) actbounds.min_x++; |
| 1373 | | if (!(summary & 0xfe)) actbounds.min_x++; |
| 1374 | | break; |
| 1375 | | } |
| 1376 | | } |
| 1377 | | |
| 1378 | | // determine the actual right of the character |
| 1379 | | for (actbounds.max_x = rowbytes - 1; actbounds.max_x >= 0; actbounds.max_x--) |
| 1380 | | { |
| 1381 | | BYTE *offs = bits + actbounds.max_x; |
| 1382 | | UINT8 summary = 0; |
| 1383 | | for (int y = 0; y < bmheight; y++) |
| 1384 | | summary |= offs[y * rowbytes]; |
| 1385 | | if (summary != 0) |
| 1386 | | { |
| 1387 | | actbounds.max_x *= 8; |
| 1388 | | if (summary & 0x7f) actbounds.max_x++; |
| 1389 | | if (summary & 0x3f) actbounds.max_x++; |
| 1390 | | if (summary & 0x1f) actbounds.max_x++; |
| 1391 | | if (summary & 0x0f) actbounds.max_x++; |
| 1392 | | if (summary & 0x07) actbounds.max_x++; |
| 1393 | | if (summary & 0x03) actbounds.max_x++; |
| 1394 | | if (summary & 0x01) actbounds.max_x++; |
| 1395 | | break; |
| 1396 | | } |
| 1397 | | } |
| 1398 | | |
| 1399 | | // allocate a new bitmap |
| 1400 | | if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y) |
| 1401 | | { |
| 1402 | | bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y); |
| 1403 | | |
| 1404 | | // copy the bits into it |
| 1405 | | for (int y = 0; y < bitmap.height(); y++) |
| 1406 | | { |
| 1407 | | UINT32 *dstrow = &bitmap.pix32(y); |
| 1408 | | UINT8 *srcrow = &bits[(y + actbounds.min_y) * rowbytes]; |
| 1409 | | for (int x = 0; x < bitmap.width(); x++) |
| 1410 | | { |
| 1411 | | int effx = x + actbounds.min_x; |
| 1412 | | dstrow[x] = ((srcrow[effx / 8] << (effx % 8)) & 0x80) ? rgb_t(0xff, 0xff, 0xff, 0xff) : rgb_t(0x00, 0xff, 0xff, 0xff); |
| 1413 | | } |
| 1414 | | } |
| 1415 | | |
| 1416 | | // set the final offset values |
| 1417 | | xoffs = actbounds.min_x - (50 + abc.abcA); |
| 1418 | | yoffs = actbounds.max_y - (50 + metrics.tmAscent); |
| 1419 | | } |
| 1420 | | |
| 1421 | | // de-select the font and release the DC |
| 1422 | | SelectObject(dummyDC, oldbitmap); |
| 1423 | | DeleteObject(dib); |
| 1424 | | SelectObject(dummyDC, oldfont); |
| 1425 | | DeleteDC(dummyDC); |
| 1426 | | return bitmap.valid(); |
| 1427 | | } |
| 1428 | | |
| 1429 | | #else |
| 1430 | | |
| 1431 | | //------------------------------------------------- |
| 1432 | | // font_open - attempt to "open" a handle to the |
| 1433 | | // font with the given name |
| 1434 | | //------------------------------------------------- |
| 1435 | | |
| 1436 | | osd_font *sdl_osd_interface::font_open(const char *_name, int &height) |
| 1437 | | { |
| 1438 | | return (osd_font *)NULL; |
| 1439 | | } |
| 1440 | | |
| 1441 | | //------------------------------------------------- |
| 1442 | | // font_close - release resources associated with |
| 1443 | | // a given OSD font |
| 1444 | | //------------------------------------------------- |
| 1445 | | |
| 1446 | | void sdl_osd_interface::font_close(osd_font *font) |
| 1447 | | { |
| 1448 | | } |
| 1449 | | |
| 1450 | | //------------------------------------------------- |
| 1451 | | // font_get_bitmap - allocate and populate a |
| 1452 | | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 1453 | | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 1454 | | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 1455 | | // pixel of a black & white font |
| 1456 | | //------------------------------------------------- |
| 1457 | | |
| 1458 | | bool sdl_osd_interface::font_get_bitmap(osd_font *font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 1459 | | { |
| 1460 | | return false; |
| 1461 | | } |
| 1462 | 753 | #endif |
| 1463 | | #endif |
| 1464 | 754 | |
| 1465 | 755 | |
trunk/src/osd/windows/winmain.c
| r243010 | r243011 | |
| 713 | 713 | winwindow_process_events(machine(), 0, 0); |
| 714 | 714 | } |
| 715 | 715 | |
| 716 | | |
| 717 | | //------------------------------------------------- |
| 718 | | // font_open - attempt to "open" a handle to the |
| 719 | | // font with the given name |
| 720 | | //------------------------------------------------- |
| 721 | | |
| 722 | | osd_font *windows_osd_interface::font_open(const char *_name, int &height) |
| 723 | | { |
| 724 | | // accept qualifiers from the name |
| 725 | | astring name(_name); |
| 726 | | if (name == "default") name = "Tahoma"; |
| 727 | | bool bold = (name.replace(0, "[B]", "") + name.replace(0, "[b]", "") > 0); |
| 728 | | bool italic = (name.replace(0, "[I]", "") + name.replace(0, "[i]", "") > 0); |
| 729 | | |
| 730 | | // build a basic LOGFONT description of what we want |
| 731 | | LOGFONT logfont; |
| 732 | | logfont.lfHeight = DEFAULT_FONT_HEIGHT; |
| 733 | | logfont.lfWidth = 0; |
| 734 | | logfont.lfEscapement = 0; |
| 735 | | logfont.lfOrientation = 0; |
| 736 | | logfont.lfWeight = bold ? FW_BOLD : FW_MEDIUM; |
| 737 | | logfont.lfItalic = italic; |
| 738 | | logfont.lfUnderline = FALSE; |
| 739 | | logfont.lfStrikeOut = FALSE; |
| 740 | | logfont.lfCharSet = ANSI_CHARSET; |
| 741 | | logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; |
| 742 | | logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
| 743 | | logfont.lfQuality = NONANTIALIASED_QUALITY; |
| 744 | | logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
| 745 | | |
| 746 | | // copy in the face name |
| 747 | | TCHAR *face = tstring_from_utf8(name); |
| 748 | | _tcsncpy(logfont.lfFaceName, face, sizeof(logfont.lfFaceName) / sizeof(TCHAR)); |
| 749 | | logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR) - 1] = 0; |
| 750 | | osd_free(face); |
| 751 | | |
| 752 | | // create the font |
| 753 | | height = logfont.lfHeight; |
| 754 | | osd_font *font = reinterpret_cast<osd_font *>(CreateFontIndirect(&logfont)); |
| 755 | | if (font == NULL) |
| 756 | | return NULL; |
| 757 | | |
| 758 | | // select it into a temp DC and get the real font name |
| 759 | | HDC dummyDC = CreateCompatibleDC(NULL); |
| 760 | | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 761 | | TCHAR realname[100]; |
| 762 | | GetTextFace(dummyDC, ARRAY_LENGTH(realname), realname); |
| 763 | | SelectObject(dummyDC, oldfont); |
| 764 | | DeleteDC(dummyDC); |
| 765 | | |
| 766 | | // if it doesn't match our request, fail |
| 767 | | char *utf = utf8_from_tstring(realname); |
| 768 | | int result = core_stricmp(utf, name); |
| 769 | | osd_free(utf); |
| 770 | | |
| 771 | | // if we didn't match, nuke our font and fall back |
| 772 | | if (result != 0) |
| 773 | | { |
| 774 | | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 775 | | font = NULL; |
| 776 | | } |
| 777 | | return font; |
| 778 | | } |
| 779 | | |
| 780 | | |
| 781 | | //------------------------------------------------- |
| 782 | | // font_close - release resources associated with |
| 783 | | // a given OSD font |
| 784 | | //------------------------------------------------- |
| 785 | | |
| 786 | | void windows_osd_interface::font_close(osd_font *font) |
| 787 | | { |
| 788 | | // delete the font ojbect |
| 789 | | if (font != NULL) |
| 790 | | DeleteObject(reinterpret_cast<HFONT>(font)); |
| 791 | | } |
| 792 | | |
| 793 | | |
| 794 | | //------------------------------------------------- |
| 795 | | // font_get_bitmap - allocate and populate a |
| 796 | | // BITMAP_FORMAT_ARGB32 bitmap containing the |
| 797 | | // pixel values rgb_t(0xff,0xff,0xff,0xff) |
| 798 | | // or rgb_t(0x00,0xff,0xff,0xff) for each |
| 799 | | // pixel of a black & white font |
| 800 | | //------------------------------------------------- |
| 801 | | |
| 802 | | bool windows_osd_interface::font_get_bitmap(osd_font *font, unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) |
| 803 | | { |
| 804 | | // create a dummy DC to work with |
| 805 | | HDC dummyDC = CreateCompatibleDC(NULL); |
| 806 | | HGDIOBJ oldfont = SelectObject(dummyDC, reinterpret_cast<HGDIOBJ>(font)); |
| 807 | | |
| 808 | | // get the text metrics |
| 809 | | TEXTMETRIC metrics = { 0 }; |
| 810 | | GetTextMetrics(dummyDC, &metrics); |
| 811 | | |
| 812 | | // get the width of this character |
| 813 | | ABC abc; |
| 814 | | if (!GetCharABCWidths(dummyDC, chnum, chnum, &abc)) |
| 815 | | { |
| 816 | | abc.abcA = 0; |
| 817 | | abc.abcC = 0; |
| 818 | | GetCharWidth32(dummyDC, chnum, chnum, reinterpret_cast<LPINT>(&abc.abcB)); |
| 819 | | } |
| 820 | | width = abc.abcA + abc.abcB + abc.abcC; |
| 821 | | |
| 822 | | // determine desired bitmap size |
| 823 | | int bmwidth = (50 + abc.abcA + abc.abcB + abc.abcC + 50 + 31) & ~31; |
| 824 | | int bmheight = 50 + metrics.tmHeight + 50; |
| 825 | | |
| 826 | | // describe the bitmap we want |
| 827 | | BYTE bitmapinfodata[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)] = { 0 }; |
| 828 | | BITMAPINFO &info = *reinterpret_cast<BITMAPINFO *>(bitmapinfodata); |
| 829 | | info.bmiHeader.biSize = sizeof(info.bmiHeader); |
| 830 | | info.bmiHeader.biWidth = bmwidth; |
| 831 | | info.bmiHeader.biHeight = -bmheight; |
| 832 | | info.bmiHeader.biPlanes = 1; |
| 833 | | info.bmiHeader.biBitCount = 1; |
| 834 | | info.bmiHeader.biCompression = BI_RGB; |
| 835 | | info.bmiHeader.biSizeImage = 0; |
| 836 | | info.bmiHeader.biXPelsPerMeter = GetDeviceCaps(dummyDC, HORZRES) / GetDeviceCaps(dummyDC, HORZSIZE); |
| 837 | | info.bmiHeader.biYPelsPerMeter = GetDeviceCaps(dummyDC, VERTRES) / GetDeviceCaps(dummyDC, VERTSIZE); |
| 838 | | info.bmiHeader.biClrUsed = 0; |
| 839 | | info.bmiHeader.biClrImportant = 0; |
| 840 | | RGBQUAD col1 = info.bmiColors[0]; |
| 841 | | RGBQUAD col2 = info.bmiColors[1]; |
| 842 | | col1.rgbBlue = col1.rgbGreen = col1.rgbRed = 0x00; |
| 843 | | col2.rgbBlue = col2.rgbGreen = col2.rgbRed = 0xff; |
| 844 | | |
| 845 | | // create a DIB to render to |
| 846 | | BYTE *bits; |
| 847 | | HBITMAP dib = CreateDIBSection(dummyDC, &info, DIB_RGB_COLORS, reinterpret_cast<VOID **>(&bits), NULL, 0); |
| 848 | | HGDIOBJ oldbitmap = SelectObject(dummyDC, dib); |
| 849 | | |
| 850 | | // clear the bitmap |
| 851 | | int rowbytes = bmwidth / 8; |
| 852 | | memset(bits, 0, rowbytes * bmheight); |
| 853 | | |
| 854 | | // now draw the character |
| 855 | | WCHAR tempchar = chnum; |
| 856 | | SetTextColor(dummyDC, RGB(0xff,0xff,0xff)); |
| 857 | | SetBkColor(dummyDC, RGB(0x00,0x00,0x00)); |
| 858 | | ExtTextOutW(dummyDC, 50 + abc.abcA, 50, ETO_OPAQUE, NULL, &tempchar, 1, NULL); |
| 859 | | |
| 860 | | // characters are expected to be full-height |
| 861 | | rectangle actbounds; |
| 862 | | actbounds.min_y = 50; |
| 863 | | actbounds.max_y = 50 + metrics.tmHeight - 1; |
| 864 | | |
| 865 | | // determine the actual left of the character |
| 866 | | for (actbounds.min_x = 0; actbounds.min_x < rowbytes; actbounds.min_x++) |
| 867 | | { |
| 868 | | BYTE *offs = bits + actbounds.min_x; |
| 869 | | UINT8 summary = 0; |
| 870 | | for (int y = 0; y < bmheight; y++) |
| 871 | | summary |= offs[y * rowbytes]; |
| 872 | | if (summary != 0) |
| 873 | | { |
| 874 | | actbounds.min_x *= 8; |
| 875 | | if (!(summary & 0x80)) actbounds.min_x++; |
| 876 | | if (!(summary & 0xc0)) actbounds.min_x++; |
| 877 | | if (!(summary & 0xe0)) actbounds.min_x++; |
| 878 | | if (!(summary & 0xf0)) actbounds.min_x++; |
| 879 | | if (!(summary & 0xf8)) actbounds.min_x++; |
| 880 | | if (!(summary & 0xfc)) actbounds.min_x++; |
| 881 | | if (!(summary & 0xfe)) actbounds.min_x++; |
| 882 | | break; |
| 883 | | } |
| 884 | | } |
| 885 | | |
| 886 | | // determine the actual right of the character |
| 887 | | for (actbounds.max_x = rowbytes - 1; actbounds.max_x >= 0; actbounds.max_x--) |
| 888 | | { |
| 889 | | BYTE *offs = bits + actbounds.max_x; |
| 890 | | UINT8 summary = 0; |
| 891 | | for (int y = 0; y < bmheight; y++) |
| 892 | | summary |= offs[y * rowbytes]; |
| 893 | | if (summary != 0) |
| 894 | | { |
| 895 | | actbounds.max_x *= 8; |
| 896 | | if (summary & 0x7f) actbounds.max_x++; |
| 897 | | if (summary & 0x3f) actbounds.max_x++; |
| 898 | | if (summary & 0x1f) actbounds.max_x++; |
| 899 | | if (summary & 0x0f) actbounds.max_x++; |
| 900 | | if (summary & 0x07) actbounds.max_x++; |
| 901 | | if (summary & 0x03) actbounds.max_x++; |
| 902 | | if (summary & 0x01) actbounds.max_x++; |
| 903 | | break; |
| 904 | | } |
| 905 | | } |
| 906 | | |
| 907 | | // allocate a new bitmap |
| 908 | | if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y) |
| 909 | | { |
| 910 | | bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y); |
| 911 | | |
| 912 | | // copy the bits into it |
| 913 | | for (int y = 0; y < bitmap.height(); y++) |
| 914 | | { |
| 915 | | UINT32 *dstrow = &bitmap.pix32(y); |
| 916 | | UINT8 *srcrow = &bits[(y + actbounds.min_y) * rowbytes]; |
| 917 | | for (int x = 0; x < bitmap.width(); x++) |
| 918 | | { |
| 919 | | int effx = x + actbounds.min_x; |
| 920 | | dstrow[x] = ((srcrow[effx / 8] << (effx % 8)) & 0x80) ? rgb_t(0xff,0xff,0xff,0xff) : rgb_t(0x00,0xff,0xff,0xff); |
| 921 | | } |
| 922 | | } |
| 923 | | |
| 924 | | // set the final offset values |
| 925 | | xoffs = actbounds.min_x - (50 + abc.abcA); |
| 926 | | yoffs = actbounds.max_y - (50 + metrics.tmAscent); |
| 927 | | } |
| 928 | | |
| 929 | | // de-select the font and release the DC |
| 930 | | SelectObject(dummyDC, oldbitmap); |
| 931 | | DeleteObject(dib); |
| 932 | | SelectObject(dummyDC, oldfont); |
| 933 | | DeleteDC(dummyDC); |
| 934 | | return bitmap.valid(); |
| 935 | | } |
| 936 | | |
| 937 | | |
| 938 | 716 | //============================================================ |
| 939 | 717 | // winmain_dump_stack |
| 940 | 718 | //============================================================ |