|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-7 by Raw Material Software ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the
- GNU General Public License, as published by the Free Software Foundation;
- either version 2 of the License, or (at your option) any later version.
-
- JUCE is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with JUCE; if not, visit www.gnu.org/licenses or write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ------------------------------------------------------------------------------
-
- If you'd like to release a closed-source product which uses JUCE, commercial
- licenses are also available: visit www.rawmaterialsoftware.com/juce for
- more information.
-
- ==============================================================================
- */
-
- #include "win32_headers.h"
- #include "../../../src/juce_core/basics/juce_StandardHeader.h"
-
- BEGIN_JUCE_NAMESPACE
-
- #include "../../../src/juce_appframework/gui/graphics/fonts/juce_Font.h"
- #include "../../../src/juce_appframework/application/juce_DeletedAtShutdown.h"
- #include "../../../src/juce_core/basics/juce_SystemStats.h"
- #include "../../../src/juce_core/basics/juce_Singleton.h"
- #include "../../../src/juce_appframework/gui/graphics/imaging/juce_Image.h"
-
-
- //==============================================================================
- static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe,
- NEWTEXTMETRICEXW*,
- int type,
- LPARAM lParam)
- {
- if (lpelfe != 0 && type == TRUETYPE_FONTTYPE)
- {
- const String fontName (lpelfe->elfLogFont.lfFaceName);
-
- ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters (T("@")));
- }
-
- return 1;
- }
-
- static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe,
- NEWTEXTMETRICEXW*,
- int type,
- LPARAM lParam)
- {
- if (lpelfe != 0
- && ((type & (DEVICE_FONTTYPE | RASTER_FONTTYPE)) == 0))
- {
- LOGFONTW lf;
- zerostruct (lf);
-
- lf.lfWeight = FW_DONTCARE;
- lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
- lf.lfQuality = DEFAULT_QUALITY;
- lf.lfCharSet = DEFAULT_CHARSET;
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf.lfPitchAndFamily = FF_DONTCARE;
-
- const String fontName (lpelfe->elfLogFont.lfFaceName);
- fontName.copyToBuffer (lf.lfFaceName, LF_FACESIZE - 1);
-
- HDC dc = CreateCompatibleDC (0);
- EnumFontFamiliesEx (dc, &lf,
- (FONTENUMPROCW) &wfontEnum2,
- lParam, 0);
- DeleteDC (dc);
- }
-
- return 1;
- }
-
- const StringArray Font::findAllTypefaceNames() throw()
- {
- StringArray results;
- HDC dc = CreateCompatibleDC (0);
-
- {
- LOGFONTW lf;
- zerostruct (lf);
-
- lf.lfWeight = FW_DONTCARE;
- lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
- lf.lfQuality = DEFAULT_QUALITY;
- lf.lfCharSet = DEFAULT_CHARSET;
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf.lfPitchAndFamily = FF_DONTCARE;
- lf.lfFaceName[0] = 0;
-
- EnumFontFamiliesEx (dc, &lf,
- (FONTENUMPROCW) &wfontEnum1,
- (LPARAM) &results, 0);
- }
-
- DeleteDC (dc);
-
- results.sort (true);
- return results;
- }
-
- extern bool juce_IsRunningInWine() throw();
-
- void Font::getDefaultFontNames (String& defaultSans,
- String& defaultSerif,
- String& defaultFixed) throw()
- {
- if (juce_IsRunningInWine())
- {
- // If we're running in Wine, then use fonts that might be available on Linux..
- defaultSans = "Bitstream Vera Sans";
- defaultSerif = "Bitstream Vera Serif";
- defaultFixed = "Bitstream Vera Sans Mono";
- }
- else
- {
- defaultSans = "Verdana";
- defaultSerif = "Times";
- defaultFixed = "Lucida Console";
- }
- }
-
- //==============================================================================
- class FontDCHolder : private DeletedAtShutdown
- {
- HDC dc;
- String fontName;
- KERNINGPAIR* kps;
- int numKPs;
- bool bold, italic;
- int size;
-
- FontDCHolder (const FontDCHolder&);
- const FontDCHolder& operator= (const FontDCHolder&);
-
- public:
- HFONT fontH;
-
- //==============================================================================
- FontDCHolder() throw()
- : dc (0),
- kps (0),
- numKPs (0),
- bold (false),
- italic (false),
- size (0)
- {
- }
-
- ~FontDCHolder() throw()
- {
- if (dc != 0)
- {
- DeleteDC (dc);
- DeleteObject (fontH);
- juce_free (kps);
- }
-
- clearSingletonInstance();
- }
-
- juce_DeclareSingleton_SingleThreaded_Minimal (FontDCHolder);
-
- //==============================================================================
- HDC loadFont (const String& fontName_,
- const bool bold_,
- const bool italic_,
- const int size_) throw()
- {
- if (fontName != fontName_ || bold != bold_ || italic != italic_ || size != size_)
- {
- fontName = fontName_;
- bold = bold_;
- italic = italic_;
- size = size_;
-
- if (dc != 0)
- {
- DeleteDC (dc);
- DeleteObject (fontH);
-
- juce_free (kps);
- kps = 0;
- }
-
- fontH = 0;
-
- dc = CreateCompatibleDC (0);
- SetMapperFlags (dc, 0);
- SetMapMode (dc, MM_TEXT);
-
- LOGFONTW lfw;
- zerostruct (lfw);
-
- lfw.lfCharSet = DEFAULT_CHARSET;
- lfw.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lfw.lfOutPrecision = OUT_OUTLINE_PRECIS;
- lfw.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- lfw.lfQuality = PROOF_QUALITY;
- lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE);
- lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL;
- fontName.copyToBuffer (lfw.lfFaceName, LF_FACESIZE - 1);
-
- lfw.lfHeight = size > 0 ? size : -256;
- HFONT standardSizedFont = CreateFontIndirect (&lfw);
-
- if (standardSizedFont != 0)
- {
- if (SelectObject (dc, standardSizedFont) != 0)
- {
- fontH = standardSizedFont;
-
- if (size == 0)
- {
- OUTLINETEXTMETRIC otm;
- if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0)
- {
- lfw.lfHeight = -(int) otm.otmEMSquare;
- fontH = CreateFontIndirect (&lfw);
-
- SelectObject (dc, fontH);
- DeleteObject (standardSizedFont);
- }
- }
- }
- else
- {
- jassertfalse
- }
- }
- else
- {
- jassertfalse
- }
- }
-
- return dc;
- }
-
- //==============================================================================
- KERNINGPAIR* getKerningPairs (int& numKPs_) throw()
- {
- if (kps == 0)
- {
- numKPs = GetKerningPairs (dc, 0, 0);
- kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs);
- GetKerningPairs (dc, numKPs, kps);
- }
-
- numKPs_ = numKPs;
- return kps;
- }
- };
-
- juce_ImplementSingleton_SingleThreaded (FontDCHolder);
-
-
- //==============================================================================
- static bool addGlyphToTypeface (HDC dc,
- juce_wchar character,
- Typeface& dest,
- bool addKerning)
- {
- Path destShape;
- GLYPHMETRICS gm;
-
- float height;
- BOOL ok = false;
-
- {
- const WCHAR charToTest[] = { (WCHAR) character, 0 };
- WORD index = 0;
-
- if (GetGlyphIndices (dc, charToTest, 1, &index, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR
- && index == 0xffff)
- {
- return false;
- }
- }
-
- TEXTMETRIC tm;
- ok = GetTextMetrics (dc, &tm);
-
- height = (float) tm.tmHeight;
-
- if (! ok)
- {
- dest.addGlyph (character, destShape, 0);
- return true;
- }
-
- const float scaleX = 1.0f / height;
- const float scaleY = -1.0f / height;
- static const MAT2 identityMatrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
-
- const int bufSize = GetGlyphOutline (dc, character, GGO_NATIVE,
- &gm, 0, 0, &identityMatrix);
-
- if (bufSize > 0)
- {
- char* const data = (char*) juce_malloc (bufSize);
-
- GetGlyphOutline (dc, character, GGO_NATIVE, &gm,
- bufSize, data, &identityMatrix);
-
- const TTPOLYGONHEADER* pheader = (TTPOLYGONHEADER*) data;
-
- while ((char*) pheader < data + bufSize)
- {
- #define remapX(v) (scaleX * (v).x.value)
- #define remapY(v) (scaleY * (v).y.value)
-
- float x = remapX (pheader->pfxStart);
- float y = remapY (pheader->pfxStart);
-
- destShape.startNewSubPath (x, y);
-
- const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER));
- const char* const curveEnd = ((const char*) pheader) + pheader->cb;
-
- while ((const char*) curve < curveEnd)
- {
- if (curve->wType == TT_PRIM_LINE)
- {
- for (int i = 0; i < curve->cpfx; ++i)
- {
- x = remapX (curve->apfx [i]);
- y = remapY (curve->apfx [i]);
-
- destShape.lineTo (x, y);
- }
- }
- else if (curve->wType == TT_PRIM_QSPLINE)
- {
- for (int i = 0; i < curve->cpfx - 1; ++i)
- {
- const float x2 = remapX (curve->apfx [i]);
- const float y2 = remapY (curve->apfx [i]);
- float x3, y3;
-
- if (i < curve->cpfx - 2)
- {
- x3 = 0.5f * (x2 + remapX (curve->apfx [i + 1]));
- y3 = 0.5f * (y2 + remapY (curve->apfx [i + 1]));
- }
- else
- {
- x3 = remapX (curve->apfx [i + 1]);
- y3 = remapY (curve->apfx [i + 1]);
- }
-
- destShape.quadraticTo (x2, y2, x3, y3);
-
- x = x3;
- y = y3;
- }
- }
-
- curve = (const TTPOLYCURVE*) &(curve->apfx [curve->cpfx]);
- }
-
- pheader = (const TTPOLYGONHEADER*) curve;
-
- destShape.closeSubPath();
- }
-
- juce_free (data);
- }
-
- dest.addGlyph (character, destShape, gm.gmCellIncX / height);
-
- if (addKerning)
- {
- int numKPs;
- const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
-
- for (int i = 0; i < numKPs; ++i)
- {
- if (kps[i].wFirst == character)
- {
- dest.addKerningPair (kps[i].wFirst,
- kps[i].wSecond,
- kps[i].iKernAmount / height);
- }
- }
- }
-
- return true;
- }
-
- //==============================================================================
- bool Typeface::findAndAddSystemGlyph (juce_wchar character) throw()
- {
- HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), 0);
- return addGlyphToTypeface (dc, character, *this, true);
- }
-
- /*Image* Typeface::renderGlyphToImage (juce_wchar character, float& topLeftX, float& topLeftY)
- {
- HDC dc = FontDCHolder::getInstance()->loadFont (getName(), isBold(), isItalic(), hintingSize);
-
- int bufSize;
- GLYPHMETRICS gm;
-
- const UINT format = GGO_GRAY2_BITMAP;
- const int shift = 6;
-
- if (wGetGlyphOutlineW != 0)
- bufSize = wGetGlyphOutlineW (dc, character, format, &gm, 0, 0, &identityMatrix);
- else
- bufSize = GetGlyphOutline (dc, character, format, &gm, 0, 0, &identityMatrix);
-
- Image* im = new Image (Image::SingleChannel, jmax (1, gm.gmBlackBoxX), jmax (1, gm.gmBlackBoxY), true);
-
- if (bufSize > 0)
- {
- topLeftX = (float) gm.gmptGlyphOrigin.x;
- topLeftY = (float) -gm.gmptGlyphOrigin.y;
-
- uint8* const data = (uint8*) juce_calloc (bufSize);
-
- if (wGetGlyphOutlineW != 0)
- wGetGlyphOutlineW (dc, character, format, &gm, bufSize, data, &identityMatrix);
- else
- GetGlyphOutline (dc, character, format, &gm, bufSize, data, &identityMatrix);
-
- const int stride = ((gm.gmBlackBoxX + 3) & ~3);
-
- for (int y = gm.gmBlackBoxY; --y >= 0;)
- {
- for (int x = gm.gmBlackBoxX; --x >= 0;)
- {
- const int level = data [x + y * stride] << shift;
-
- if (level > 0)
- im->setPixelAt (x, y, Colour ((uint8) 0xff, (uint8) 0xff, (uint8) 0xff, (uint8) jmin (0xff, level)));
- }
- }
-
- juce_free (data);
- }
-
- return im;
- }*/
-
- //==============================================================================
- void Typeface::initialiseTypefaceCharacteristics (const String& fontName,
- bool bold,
- bool italic,
- bool addAllGlyphsToFont) throw()
- {
- clear();
-
- HDC dc = FontDCHolder::getInstance()->loadFont (fontName, bold, italic, 0);
-
- float height;
- int firstChar, lastChar;
-
- {
- TEXTMETRIC tm;
- GetTextMetrics (dc, &tm);
-
- height = (float) tm.tmHeight;
- firstChar = tm.tmFirstChar;
- lastChar = tm.tmLastChar;
-
- setAscent (tm.tmAscent / height);
- setDefaultCharacter (tm.tmDefaultChar);
- }
-
- setName (fontName);
- setBold (bold);
- setItalic (italic);
-
- if (addAllGlyphsToFont)
- {
- for (int character = firstChar; character <= lastChar; ++character)
- addGlyphToTypeface (dc, (juce_wchar) character, *this, false);
-
- int numKPs;
- const KERNINGPAIR* const kps = FontDCHolder::getInstance()->getKerningPairs (numKPs);
-
- for (int i = 0; i < numKPs; ++i)
- {
- addKerningPair (kps[i].wFirst,
- kps[i].wSecond,
- kps[i].iKernAmount / height);
- }
- }
- }
-
- END_JUCE_NAMESPACE
|