123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platformWin32/platformWin32.h"
- #include "platformWin32/winFont.h"
- #include "gfx/gFont.h"
- #include "gfx/bitmap/gBitmap.h"
- #include "math/mRect.h"
- #include "console/console.h"
- #include "core/strings/unicode.h"
- #include "core/strings/stringFunctions.h"
- #include "core/stringTable.h"
- static HDC fontHDC = NULL;
- static HBITMAP fontBMP = NULL;
- static U32 charsetMap[]=
- {
- ANSI_CHARSET,
- SYMBOL_CHARSET,
- SHIFTJIS_CHARSET,
- HANGEUL_CHARSET,
- HANGUL_CHARSET,
- GB2312_CHARSET,
- CHINESEBIG5_CHARSET,
- OEM_CHARSET,
- JOHAB_CHARSET,
- HEBREW_CHARSET,
- ARABIC_CHARSET,
- GREEK_CHARSET,
- TURKISH_CHARSET,
- VIETNAMESE_CHARSET,
- THAI_CHARSET,
- EASTEUROPE_CHARSET,
- RUSSIAN_CHARSET,
- MAC_CHARSET,
- BALTIC_CHARSET,
- };
- #define NUMCHARSETMAP (sizeof(charsetMap) / sizeof(U32))
- void createFontInit(void);
- void createFontShutdown(void);
- void CopyCharToBitmap(GBitmap *pDstBMP, HDC hSrcHDC, const RectI &r);
- void createFontInit()
- {
- //shared library sets the appInstance here
- winState.appInstance = GetModuleHandle(NULL);
- fontHDC = CreateCompatibleDC(NULL);
- fontBMP = CreateCompatibleBitmap(fontHDC, 256, 256);
- }
- void createFontShutdown()
- {
- DeleteObject(fontBMP);
- DeleteObject(fontHDC);
- }
- void CopyCharToBitmap(GBitmap *pDstBMP, HDC hSrcHDC, const RectI &r)
- {
- for (S32 i = r.point.y; i < r.point.y + r.extent.y; i++)
- {
- for (S32 j = r.point.x; j < r.point.x + r.extent.x; j++)
- {
- COLORREF color = GetPixel(hSrcHDC, j, i);
- if (color)
- *pDstBMP->getAddress(j, i) = 255;
- else
- *pDstBMP->getAddress(j, i) = 0;
- }
- }
- }
- //-----------------------------------------------------------------------------
- // WinFont class
- //-----------------------------------------------------------------------------
- BOOL CALLBACK EnumFamCallBack(LPLOGFONT logFont, LPNEWTEXTMETRIC textMetric, DWORD fontType, LPARAM lParam)
- {
- if( !( fontType & TRUETYPE_FONTTYPE ) )
- return true;
- Vector<StringTableEntry>* fonts = (Vector< StringTableEntry>*)lParam;
- const U32 len = dStrlen( logFont->lfFaceName ) * 3 + 1;
- FrameTemp<UTF8> buffer( len );
- convertUTF16toUTF8N( logFont->lfFaceName, buffer, len );
- fonts->push_back( StringTable->insert( buffer ) );
- return true;
- }
- void PlatformFont::enumeratePlatformFonts( Vector<StringTableEntry>& fonts, UTF16* fontFamily )
- {
- EnumFontFamilies( fontHDC, fontFamily, (FONTENUMPROC)EnumFamCallBack, (LPARAM)&fonts );
- }
- PlatformFont *createPlatformFont(const char *name, dsize_t size, U32 charset /* = TGE_ANSI_CHARSET */)
- {
- PlatformFont *retFont = new WinFont;
- if(retFont->create(name, size, charset))
- return retFont;
- delete retFont;
- return NULL;
- }
- WinFont::WinFont() : mFont(NULL)
- {
- dMemset(&mTextMetric, 0, sizeof(mTextMetric));
- }
- WinFont::~WinFont()
- {
- if(mFont)
- {
- DeleteObject(mFont);
- }
- }
- bool WinFont::create(const char *name, dsize_t size, U32 charset /* = TGE_ANSI_CHARSET */)
- {
- if(name == NULL || size < 1)
- return false;
- if(charset > NUMCHARSETMAP)
- charset = TGE_ANSI_CHARSET;
- U32 weight = 0;
- U32 doItalic = 0;
- String nameStr = name;
- nameStr = nameStr.trim();
-
- bool haveModifier;
- do
- {
- haveModifier = false;
- if( nameStr.compare( "Bold", 4, String::NoCase | String::Right ) == 0 )
- {
- weight = 700;
- nameStr = nameStr.substr( 0, nameStr.length() - 4 ).trim();
- haveModifier = true;
- }
- if( nameStr.compare( "Italic", 6, String::NoCase | String::Right ) == 0 )
- {
- doItalic = 1;
- nameStr = nameStr.substr( 0, nameStr.length() - 6 ).trim();
- haveModifier = true;
- }
- }
- while( haveModifier );
- #ifdef UNICODE
- const UTF16* n = nameStr.utf16();
- mFont = CreateFont(size,0,0,0,weight,doItalic,0,0,DEFAULT_CHARSET,OUT_TT_PRECIS,0,PROOF_QUALITY,0,n);
- #else
- mFont = CreateFont(size,0,0,0,weight,doItalic,0,0,charsetMap[charset],OUT_TT_PRECIS,0,PROOF_QUALITY,0,name);
- #endif
- if(mFont == NULL)
- return false;
- SelectObject(fontHDC, fontBMP);
- SelectObject(fontHDC, mFont);
- GetTextMetrics(fontHDC, &mTextMetric);
- return true;
- }
- bool WinFont::isValidChar(const UTF16 ch) const
- {
- return ch != 0 /* && (ch >= mTextMetric.tmFirstChar && ch <= mTextMetric.tmLastChar)*/;
- }
- bool WinFont::isValidChar(const UTF8 *str) const
- {
- return isValidChar(oneUTF8toUTF32(str));
- }
- PlatformFont::CharInfo &WinFont::getCharInfo(const UTF16 ch) const
- {
- static PlatformFont::CharInfo c;
- dMemset(&c, 0, sizeof(c));
- c.bitmapIndex = -1;
- static U8 scratchPad[65536];
- COLORREF backgroundColorRef = RGB( 0, 0, 0);
- COLORREF foregroundColorRef = RGB(255, 255, 255);
- SelectObject(fontHDC, fontBMP);
- SelectObject(fontHDC, mFont);
- SetBkColor(fontHDC, backgroundColorRef);
- SetTextColor(fontHDC, foregroundColorRef);
-
- MAT2 matrix;
- GLYPHMETRICS metrics;
- RectI clip;
-
- FIXED zero;
- zero.fract = 0;
- zero.value = 0;
- FIXED one;
- one.fract = 0;
- one.value = 1;
-
- matrix.eM11 = one;
- matrix.eM12 = zero;
- matrix.eM21 = zero;
- matrix.eM22 = one;
- if(GetGlyphOutline(
- fontHDC, // handle of device context
- ch, // character to query
- GGO_GRAY8_BITMAP, // format of data to return
- &metrics, // address of structure for metrics
- sizeof(scratchPad), // size of buffer for data
- scratchPad, // address of buffer for data
- &matrix // address of transformation matrix structure
- ) != GDI_ERROR)
- {
- U32 rowStride = (metrics.gmBlackBoxX + 3) & ~3; // DWORD aligned
- U32 size = rowStride * metrics.gmBlackBoxY;
-
- // [neo, 5/7/2007 - #3055]
- // If we get large font sizes rowStride * metrics.gmBlackBoxY will
- // be larger than scratch pad size and so overwrite mem, boom!
- // Added range check < scratchPad for now but we need to review what
- // to do here - do we want to call GetGlyphOutline() first with null
- // values and get the real size to alloc buffer?
- //if( size > sizeof( scratchPad ) )
- // DebugBreak();
- for(U32 j = 0; j < size && j < sizeof(scratchPad); j++)
- {
- U32 pad = U32(scratchPad[j]) << 2;
- if(pad > 255)
- pad = 255;
- scratchPad[j] = pad;
- }
- S32 inc = metrics.gmCellIncX;
- if(inc < 0)
- inc = -inc;
-
- c.xOffset = 0;
- c.yOffset = 0;
- c.width = metrics.gmBlackBoxX;
- c.height = metrics.gmBlackBoxY;
- c.xOrigin = metrics.gmptGlyphOrigin.x;
- c.yOrigin = metrics.gmptGlyphOrigin.y;
- c.xIncrement = metrics.gmCellIncX;
- c.bitmapData = new U8[c.width * c.height];
- AssertFatal( c.bitmapData != NULL, "Could not allocate memory for font bitmap data!");
- for(U32 y = 0; S32(y) < c.height; y++)
- {
- U32 x;
- for(x = 0; x < c.width; x++)
- {
- // [neo, 5/7/2007 - #3055]
- // See comments above about scratchPad overrun
- S32 spi = y * rowStride + x;
- if( spi >= sizeof(scratchPad) )
- return c;
- c.bitmapData[y * c.width + x] = scratchPad[spi];
- }
- }
- }
- else
- {
- SIZE size;
- GetTextExtentPoint32W(fontHDC, &ch, 1, &size);
- if(size.cx)
- {
- c.xIncrement = size.cx;
- c.bitmapIndex = 0;
- }
- }
- return c;
- }
- PlatformFont::CharInfo &WinFont::getCharInfo(const UTF8 *str) const
- {
- return getCharInfo(oneUTF8toUTF32(str));
- }
|