fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Text / OSGTextWIN32Backend.cpp
blob75ff29a7e26336c13b17eede8986295cfa49d0f8
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 #include "OSGTextWIN32Backend.h"
40 #include "OSGBaseTypes.h"
43 #if defined(_WIN32) || defined(OSG_DO_DOC)
46 #ifdef _MSC_VER
47 # pragma warning (disable: 4786)
48 #endif
50 #include "OSGTextPixmapFace.h"
51 #include "OSGTextPixmapGlyph.h"
52 #include "OSGTextVectorFace.h"
53 #include "OSGTextVectorGlyph.h"
54 #include "OSGTextTXFFace.h"
55 #include "OSGTextTXFGlyph.h"
56 #include "OSGTextLayoutParam.h"
57 #include "OSGTextLayoutResult.h"
59 #include <iostream>
60 #include <algorithm>
61 #include <set>
64 using namespace std;
65 OSG_BEGIN_NAMESPACE
68 //----------------------------------------------------------------------
69 // WIN32 specific implementation of the TextVectorFace class
70 // Author: pdaehne
71 //----------------------------------------------------------------------
73 /*! \nohierarchy
76 class TextWIN32VectorFace: public TextVectorFace
78 public:
80 // Constructor
81 TextWIN32VectorFace(TextWIN32Backend *backend, HFONT hHoriFont, HFONT hVertFont);
83 // Destructor
84 virtual ~TextWIN32VectorFace();
86 // Lays out one line of text
87 virtual void layout(const wstring &text, const TextLayoutParam &param,
88 TextLayoutResult &layoutResult);
90 protected:
92 // Creates a new Glyph object
93 virtual unique_ptr<TextVectorGlyph> createGlyph(TextGlyph::Index glyphIndex);
95 private:
97 // The backend that created the face
98 TextWIN32Backend *_backend;
100 // Font handle for horizontal layout
101 HFONT _hHoriFont;
103 // Font handle for vertical layout
104 HFONT _hVertFont;
108 //----------------------------------------------------------------------
109 // WIN32 specific implementation of the TextVectorGlyph class
110 // Author: pdaehne
111 //----------------------------------------------------------------------
113 /*! \nohierarchy
116 class TextWIN32VectorGlyph: public TextVectorGlyph
118 public:
120 // Constructor
121 TextWIN32VectorGlyph(Index glyphIndex, Real32 scale,
122 const GLYPHMETRICS &hpgm, const GLYPHMETRICS &vhpgm,
123 LPTTPOLYGONHEADER lpHeader, DWORD size);
125 // Destructor
126 virtual ~TextWIN32VectorGlyph();
130 //----------------------------------------------------------------------
131 // WIN32 specific implementation of the TextPixmapFace class
132 // Author: pdaehne
133 //----------------------------------------------------------------------
135 /*! \nohierarchy
138 class TextWIN32PixmapFace: public TextPixmapFace
140 public:
142 // Constructor
143 TextWIN32PixmapFace(TextWIN32Backend *backend, HFONT hHoriFont, HFONT hVertFont, UInt32 size);
145 // Destructor
146 virtual ~TextWIN32PixmapFace();
148 // Lays out one line of text
149 virtual void layout(const wstring &text, const TextLayoutParam &param,
150 TextLayoutResult &layoutResult);
152 protected:
154 // Creates a new Glyph object
155 virtual unique_ptr<TextPixmapGlyph> createGlyph(TextGlyph::Index glyphIndex);
157 private:
159 // The backend that created the face
160 TextWIN32Backend *_backend;
162 // Font handle for horizontal layout
163 HFONT _hHoriFont;
165 // Font handle for vertical layout
166 HFONT _hVertFont;
170 //----------------------------------------------------------------------
171 // WIN32 specific implementation of the TextPixmapGlyph class
172 // Author: pdaehne
173 //----------------------------------------------------------------------
175 /*! \nohierarchy
178 class TextWIN32PixmapGlyph: public TextPixmapGlyph
180 public:
182 // Constructor
183 TextWIN32PixmapGlyph(Index glyphIndex, const GLYPHMETRICS &hpgm,
184 const GLYPHMETRICS &vpgm, UInt8 *pixmap);
186 // Destructor
187 virtual ~TextWIN32PixmapGlyph();
191 //----------------------------------------------------------------------
192 // WIN32 specific implementation of the TextTXFFace class
193 // Author: pdaehne
194 //----------------------------------------------------------------------
196 /*! \nohierarchy
199 class TextWIN32TXFFace: public TextTXFFace
201 public:
203 // Constructor
204 TextWIN32TXFFace(const TextWIN32Backend *backend, HFONT hHoriFont, HFONT hVertFont,
205 const TextTXFParam &param);
207 // Destructor
208 virtual ~TextWIN32TXFFace();
212 //----------------------------------------------------------------------
213 // WIN32 specific implementation of the TextTXFGlyph class
214 // Author: pdaehne
215 //----------------------------------------------------------------------
217 /*! \nohierarchy
220 class TextWIN32TXFGlyph: public TextTXFGlyph
222 public:
224 // Constructor
225 TextWIN32TXFGlyph(Index glyphIndex, TextWIN32TXFFace *face, Real32 scale,
226 const GLYPHMETRICS &hpgm, const GLYPHMETRICS &vpgm);
228 // Destructor
229 virtual ~TextWIN32TXFGlyph();
233 //----------------------------------------------------------------------
234 // Constructor
235 // Author: pdaehne
236 //----------------------------------------------------------------------
237 TextWIN32Backend::TextWIN32Backend()
238 : TextBackend(), _hDC(0)
240 // Create device context
241 _hDC = CreateDC("DISPLAY", 0, 0, 0);
242 if (_hDC == 0)
244 SWARNING << "TextWIN32Backend: Failed to create device context."
245 << std::endl;
246 return;
249 SetGraphicsMode(_hDC, GM_ADVANCED);
253 //----------------------------------------------------------------------
254 // Destructor
255 // Author: pdaehne
256 //----------------------------------------------------------------------
257 TextWIN32Backend::~TextWIN32Backend()
259 // Destroy device context
260 DeleteDC(_hDC);
264 //----------------------------------------------------------------------
265 // Helper struct used by enumFamCallBack
266 // Author: pdaehne
267 //----------------------------------------------------------------------
269 /*! \nohierarchy
272 class EnumData
274 public:
275 string fullname;
276 UINT emSize;
280 //----------------------------------------------------------------------
281 // Callback that gets called by Windows to enumerate fonts
282 // Author: pdaehne
283 //----------------------------------------------------------------------
284 static int CALLBACK enumFamCallBack(ENUMLOGFONT *lpelf, NEWTEXTMETRIC *lpntm,
285 DWORD fontType, LPARAM lParam)
287 // We are not interested in raster fonts
288 if ((fontType & RASTER_FONTTYPE) != 0)
289 return 1;
291 // Fill enumData structure
292 EnumData *enumData = reinterpret_cast<EnumData*>(lParam);
293 enumData->fullname = (const char *)lpelf->elfFullName;
294 enumData->emSize = lpntm->ntmSizeEM;
296 // Quit enumeration
297 return 0;
301 //----------------------------------------------------------------------
302 // Creates horizontal and vertical fonts from given fontname,
303 // size and style
304 // Author: pdaehne
305 //----------------------------------------------------------------------
306 void TextWIN32Backend::createFonts(const string &family, UInt32 size, TextFace::Style style,
307 HFONT &hHoriFont, HFONT &hVertFont)
309 // Initialization
310 hHoriFont = hVertFont = 0;
312 // Handle generic family names
313 string f;
314 if (family == "SERIF")
315 f = "Times New Roman";
316 else if (family == "SANS")
317 f = "Arial";
318 else if (family == "TYPEWRITER")
319 f = "Courier New";
320 else
321 f = family;
323 if (size == 0)
325 // Grrr - this is only necessary to get the EM size -pdaehne
326 EnumData enumData;
327 EnumFontFamilies(_hDC, (LPCTSTR)(f.c_str()), (FONTENUMPROC)enumFamCallBack,
328 (LPARAM)&enumData);
329 if (enumData.fullname.empty() == true)
330 return;
331 size = -enumData.emSize;
334 // Handle style
335 BYTE italic;
336 LONG weight;
337 switch (style)
339 default:
340 FWARNING(("Invalid font style parameter.\n"));
341 // intentionally fall through
342 case TextFace::STYLE_PLAIN:
343 italic = FALSE;
344 weight = FW_NORMAL;
345 break;
346 case TextFace::STYLE_BOLD:
347 italic = FALSE;
348 weight = FW_BOLD;
349 break;
350 case TextFace::STYLE_ITALIC:
351 italic = TRUE;
352 weight = FW_NORMAL;
353 break;
354 case TextFace::STYLE_BOLDITALIC:
355 italic = TRUE;
356 weight = FW_BOLD;
357 break;
360 // Create the the horizontal font
361 hHoriFont = CreateFont(size, 0, 0, 0, weight, italic, FALSE, FALSE,
362 DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS,
363 ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
364 f.c_str());
366 // Create the the vertical font
367 hVertFont = CreateFont(size, 0, -900, 0, weight, italic, FALSE, FALSE,
368 DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS,
369 ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
370 f.c_str());
374 //----------------------------------------------------------------------
375 // Creates a new vector face
376 // Author: pdaehne
377 //----------------------------------------------------------------------
378 TextVectorFaceTransitPtr TextWIN32Backend::createVectorFace(
379 const string &family, TextFace::Style style)
381 TextVectorFaceTransitPtr retVal;
383 // Try to create the font handles
384 HFONT hHoriFont, hVertFont;
385 createFonts(family, 0, style, hHoriFont, hVertFont);
386 if (hHoriFont != 0)
388 // Create the new face object
389 retVal = new TextWIN32VectorFace(this, hHoriFont, hVertFont);
392 return retVal;
396 //----------------------------------------------------------------------
397 // Creates a new pixmap face
398 // Author: pdaehne
399 //----------------------------------------------------------------------
400 TextPixmapFaceTransitPtr TextWIN32Backend::createPixmapFace(
401 const string &family, TextFace::Style style, UInt32 size)
403 TextPixmapFaceTransitPtr retVal;
405 // Try to create the font handles
406 HFONT hHoriFont, hVertFont;
407 createFonts(family, size, style, hHoriFont, hVertFont);
408 if (hHoriFont != 0)
410 // Create the new face object
411 retVal = new TextWIN32PixmapFace(this, hHoriFont, hVertFont, size);
414 return retVal;
418 //----------------------------------------------------------------------
419 // Creates a new TXF face
420 // Author: pdaehne
421 //----------------------------------------------------------------------
422 TextTXFFaceTransitPtr TextWIN32Backend::createTXFFace(
423 const string &family, TextFace::Style style, const TextTXFParam &param)
425 TextTXFFaceTransitPtr retVal;
427 // Try to create the font handles
428 HFONT hHoriFont, hVertFont;
429 createFonts(family, param.size, style, hHoriFont, hVertFont);
430 if (hHoriFont != 0)
432 // Create the new face object
433 retVal = new TextWIN32TXFFace(this, hHoriFont, hVertFont, param);
436 return retVal;
440 //----------------------------------------------------------------------
441 // Callback that gets called by Windows to enumerate fonts
442 // Author: pdaehne
443 //----------------------------------------------------------------------
444 static int CALLBACK enumFamCallBack2(ENUMLOGFONT *lpelf, NEWTEXTMETRIC *lpntm,
445 DWORD fontType, LPARAM lParam)
447 // We are not interested in raster fonts
448 if ((fontType & RASTER_FONTTYPE) != 0)
449 return 1;
451 // Fill enumData structure
452 set<string> *familySet = reinterpret_cast<set<string>*>(lParam);
453 familySet->insert(lpelf->elfLogFont.lfFaceName);
455 // Continue enumeration
456 return 1;
460 //----------------------------------------------------------------------
461 // Returns the names of all font families available
462 // Author: pdaehne
463 //----------------------------------------------------------------------
464 void TextWIN32Backend::getFontFamilies(vector<string> &families)
466 families.clear();
468 set<string> familySet;
469 EnumFontFamilies(_hDC, 0, (FONTENUMPROC)enumFamCallBack2, (LPARAM)&familySet);
470 // GRRRR, this does not work on WIN32...
471 //families.assign(familySet.begin(), familySet.end());
472 families.resize(familySet.size());
473 copy(familySet.begin(), familySet.end(), families.begin());
477 //----------------------------------------------------------------------
478 // Returns information about a given font
479 // Author: pdaehne
480 //----------------------------------------------------------------------
481 static void getFontInfo(HDC hDC, HFONT hFont, string &family,
482 TextFace::Style &style, Real32 &ascent, Real32 &descent)
484 // Select the font into the device context
485 HGDIOBJ oldFont = SelectObject(hDC, hFont);
487 // Get the name of the font
488 int nameLength = GetTextFace(hDC, 0, 0);
489 family.resize(nameLength);
490 GetTextFace(hDC, nameLength, &(family[0]));
491 // GetTextFace also puts a trailing '\0' into the string, so we have to remove it
492 family.resize(nameLength - 1);
494 // Get metrics of the font
495 TEXTMETRIC tm;
496 BOOL result = GetTextMetrics(hDC, &tm);
497 SelectObject(hDC, oldFont);
498 if (result == FALSE)
499 return;
501 // Determine the style
502 if (tm.tmWeight > (FW_NORMAL + FW_BOLD) / 2)
503 style = tm.tmItalic != 0 ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD;
504 else
505 style = tm.tmItalic != 0 ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN;
507 // Determine ascent
508 ascent = static_cast<Real32>(tm.tmAscent);
510 // Determine descent
511 descent = static_cast<Real32>(-tm.tmDescent);
515 //----------------------------------------------------------------------
516 // Constructor
517 // Author: pdaehne
518 //----------------------------------------------------------------------
519 TextWIN32VectorFace::TextWIN32VectorFace(TextWIN32Backend *backend,
520 HFONT hHoriFont, HFONT hVertFont)
521 : TextVectorFace(), _backend(backend), _hHoriFont(hHoriFont), _hVertFont(hVertFont)
523 // Get information about the font
524 getFontInfo(_backend->_hDC, _hHoriFont, _family, _style,
525 _horiAscent, _horiDescent);
527 // Determine the scale factor and adjust ascent and descent
528 _scale = 1.f / (_horiAscent - _horiDescent);
529 _horiAscent *= _scale;
530 _horiDescent *= _scale;
532 // Determine vertical ascent and descent
533 _vertAscent = -0.5f;
534 _vertDescent = 0.5f;
538 //----------------------------------------------------------------------
539 // Destructor
540 // Author: pdaehne
541 //----------------------------------------------------------------------
542 TextWIN32VectorFace::~TextWIN32VectorFace()
544 // Destroy the font objects
545 DeleteObject(_hHoriFont);
546 DeleteObject(_hVertFont);
550 //----------------------------------------------------------------------
551 // Converts a unicode string to utf16
552 // RFC2781: UTF-16, an encoding of ISO 10646
553 // Author: pdaehne
554 //----------------------------------------------------------------------
555 static void convertUnicodeToUTF16(const wstring &text, vector<WCHAR> &utf16Text)
557 wstring::size_type i, textTotalLength = text.length();
558 utf16Text.clear();
559 utf16Text.reserve(textTotalLength);
560 for (i = 0; i < textTotalLength; ++i)
562 wchar_t unicode = text[i];
563 if (unicode < 0x10000)
564 utf16Text.push_back(unicode);
565 else if (unicode < 0x110000)
567 unsigned long u = unicode - 0x10000;
568 utf16Text.push_back(0xd800 | (u >> 10));
569 utf16Text.push_back(0xdc00 | (u & 0x3ff));
575 //----------------------------------------------------------------------
576 // Lays out one line of text
577 // Author: pdaehne
578 //----------------------------------------------------------------------
579 void TextWIN32VectorFace::layout(const wstring &text, const TextLayoutParam &param,
580 TextLayoutResult &layoutResult)
582 // Initialize return values
583 layoutResult.clear();
584 if (param.horizontal == true)
585 layoutResult.textBounds[1] = _horiAscent - _horiDescent;
586 else
587 layoutResult.textBounds[0] = _vertDescent - _vertAscent;
588 layoutResult.lineBounds.push_back(layoutResult.textBounds);
590 // Convert the unicode string to utf16
591 vector<WCHAR> utf16Text;
592 convertUnicodeToUTF16(text, utf16Text);
593 vector<WCHAR>::size_type len = utf16Text.size();
594 if (len == 0)
595 return;
597 // Select the font into the device context
598 HGDIOBJ oldFont;
599 if (param.horizontal == true)
600 oldFont = SelectObject(_backend->_hDC, _hHoriFont);
601 else
602 oldFont = SelectObject(_backend->_hDC, _hVertFont);
604 GCP_RESULTSW results;
605 ZeroMemory(&results, sizeof(results));
606 results.lStructSize = sizeof(results);
607 results.lpDx = new int[len];
608 results.lpGlyphs = new WCHAR[len];
609 results.lpGlyphs[0] = 0; // needed by GCP_LIGATE
610 results.nGlyphs = UInt32(len);
611 DWORD dwFlags = GCP_GLYPHSHAPE | GCP_LIGATE | GCP_REORDER | GCP_USEKERNING;
612 int nMaxExtent = 0;
613 Real32 length = param.getLength(0);
614 if (length > 0)
616 dwFlags |= GCP_JUSTIFY | GCP_KASHIDA | GCP_MAXEXTENT;
617 nMaxExtent = length / _scale;
619 DWORD result = GetCharacterPlacementW(_backend->_hDC, &(utf16Text[0]), UInt32(len), nMaxExtent, &results, dwFlags);
620 if (result != 0)
622 layoutResult.indices.reserve(results.nGlyphs);
623 layoutResult.positions.reserve(results.nGlyphs);
624 UINT j;
625 Vec2f currPos;
626 for (j = 0; j < results.nGlyphs; ++j)
628 // Get glyph
629 const TextGlyph &glyph = getGlyph(results.lpGlyphs[j]);
631 // Calculate position
632 Vec2f pos;
633 if (param.horizontal == true)
635 pos = currPos;
636 pos[0] += glyph.getHoriBearingX();
637 pos[1] += glyph.getHoriBearingY();
638 currPos[0] += results.lpDx[j] * _scale;
640 else
642 pos = currPos;
643 pos[0] += glyph.getVertBearingX();
644 pos[1] += glyph.getVertBearingY();
645 currPos[1] -= results.lpDx[j] * _scale;
647 layoutResult.indices.push_back(results.lpGlyphs[j]);
648 layoutResult.positions.push_back(pos);
651 // Adjust the origin depending on the major and the minor alignment
652 adjustLineOrigin(param, currPos, layoutResult);
654 // Determine text bounds / line bounds
655 if (param.horizontal == true)
656 layoutResult.textBounds[0] = osgAbs(currPos.x());
657 else
658 layoutResult.textBounds[1] = osgAbs(currPos.y());
659 OSG_ASSERT(layoutResult.lineBounds.empty() == false);
660 layoutResult.lineBounds.front() = layoutResult.textBounds;
662 delete [] results.lpDx;
663 delete [] results.lpGlyphs;
665 // Unselect the font
666 SelectObject(_backend->_hDC, oldFont);
670 //----------------------------------------------------------------------
671 // Creates a new Glyph object
672 // Author: pdaehne
673 //----------------------------------------------------------------------
674 unique_ptr<TextVectorGlyph> TextWIN32VectorFace::createGlyph(TextGlyph::Index glyphIndex)
676 // We cannot create glyphs for invalid glyph indices
677 if (glyphIndex == TextGlyph::INVALID_INDEX)
678 return unique_ptr<TextVectorGlyph>();
680 // Select the vertical font into the device context
681 HGDIOBJ oldFont = SelectObject(_backend->_hDC, _hVertFont);
683 // Get the vertical metrics
684 GLYPHMETRICS vpgm;
685 MAT2 mat2 = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
686 DWORD size = GetGlyphOutlineW(_backend->_hDC, glyphIndex, GGO_METRICS | GGO_GLYPH_INDEX,
687 &vpgm, 0, 0, &mat2);
688 if (size == GDI_ERROR)
690 SelectObject(_backend->_hDC, oldFont);
691 return unique_ptr<TextVectorGlyph>();
694 // Select the horizontal font into the device context
695 SelectObject(_backend->_hDC, _hHoriFont);
697 // Get glyph outline
698 GLYPHMETRICS hpgm;
699 size = GetGlyphOutlineW(_backend->_hDC, glyphIndex, GGO_NATIVE | GGO_GLYPH_INDEX, &hpgm, 0, 0, &mat2);
700 if (size == GDI_ERROR)
702 SelectObject(_backend->_hDC, oldFont);
703 return unique_ptr<TextVectorGlyph>();
705 LPTTPOLYGONHEADER lpHeader = (LPTTPOLYGONHEADER) new char[size];
706 size = GetGlyphOutlineW(_backend->_hDC, glyphIndex, GGO_NATIVE | GGO_GLYPH_INDEX, &hpgm, size, lpHeader, &mat2);
708 // Unselect the font
709 SelectObject(_backend->_hDC, oldFont);
711 if (size == GDI_ERROR)
713 delete [] lpHeader;
714 return unique_ptr<TextVectorGlyph>();
717 // Create and return the new glyph object
718 unique_ptr<TextVectorGlyph> glyph(new TextWIN32VectorGlyph(glyphIndex, _scale,
719 hpgm, vpgm, lpHeader, size));
720 delete [] lpHeader;
721 return glyph;
725 //----------------------------------------------------------------------
726 // Constructor
727 // Author: pdaehne
728 //----------------------------------------------------------------------
729 TextWIN32VectorGlyph::TextWIN32VectorGlyph(Index glyphIndex, Real32 scale,
730 const GLYPHMETRICS &hpgm,
731 const GLYPHMETRICS &vpgm,
732 LPTTPOLYGONHEADER lpHeader,
733 DWORD size)
734 : TextVectorGlyph()
736 _glyphIndex = glyphIndex;
737 _width = static_cast<Real32>(hpgm.gmBlackBoxX) * scale;
738 _height = static_cast<Real32>(hpgm.gmBlackBoxY) * scale;
740 // Determine horizontal glyph metrics
741 _horiAdvance = static_cast<Real32>(hpgm.gmCellIncX) * scale;
742 _horiBearingX = static_cast<Real32>(hpgm.gmptGlyphOrigin.x) * scale;
743 _horiBearingY = static_cast<Real32>(hpgm.gmptGlyphOrigin.y) * scale;
745 // Determine vertical glyph metrics
746 // Hmmm, there is no useful information here for vertical layout -
747 // the values provided are just the same as for horizontal layout.
748 // So we have to guess resonable values -pdaehne
749 //_vertAdvance = static_cast<Real32>(vpgm.gmCellIncY) * scale;
750 //_vertBearingX = static_cast<Real32>(vpgm.gmptGlyphOrigin.x) * scale;
751 //_vertBearingY = static_cast<Real32>(vpgm.gmptGlyphOrigin.y) * scale;
752 _vertAdvance = -_height;
753 _vertBearingX = -_width / 2.f;
754 _vertBearingY = 0.f;
756 Vec2f offset(_horiBearingX, _horiBearingY), p;
758 // The following algorithm has been taken from MSDN article Q243285
759 // "HOWTO: Draw TrueType Glyph Outlines" - pdaehne
761 WORD i;
762 LPTTPOLYGONHEADER lpStart; // the start of the buffer
763 LPTTPOLYCURVE lpCurve; // the current curve of a contour
764 POINTFX *endPoint = 0;
766 lpStart = lpHeader;
768 // Loop until we have processed the entire buffer of contours.
769 // The buffer may contain one or more contours that begin with
770 // a TTPOLYGONHEADER. We have them all when we the end of the buffer.
771 while ((DWORD)lpHeader < (DWORD)(((LPSTR)lpStart) + size))
773 if (lpHeader->dwType == TT_POLYGON_TYPE)
774 // Draw each coutour, currently this is the only valid
775 // type of contour.
777 _outline.push_back(TextVectorGlyph::Contour());
779 // Convert the starting point. It is an on curve point.
780 // All other points are continuous from the "last"
781 // point of the contour. Thus the start point the next
782 // bezier is always pt[cTotal-1] - the last point of the
783 // previous bezier. See PolyBezier.
784 POINTFX &startPoint = lpHeader->pfxStart;
785 p.setValues(startPoint.x.value, startPoint.y.value);
786 p *= scale;
787 p -= offset;
788 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
790 // Get to first curve of contour -
791 // it starts at the next byte beyond header
792 lpCurve = (LPTTPOLYCURVE) (lpHeader + 1);
794 // Walk this contour and process each curve (or line) segment
795 // and add it to the Beziers
796 while ((DWORD)lpCurve < (DWORD)(((LPSTR)lpHeader) + lpHeader->cb))
798 //**********************************************
799 // Format assumption:
800 // The bytes immediately preceding a POLYCURVE
801 // structure contain a valid POINTFX.
803 // If this is first curve, this points to the
804 // pfxStart of the POLYGONHEADER.
805 // Otherwise, this points to the last point of
806 // the previous POLYCURVE.
808 // In either case, this is representative of the
809 // previous curve's last point.
810 //**********************************************
812 if (lpCurve->wType == TT_PRIM_LINE)
814 // All point are on the curve
815 for (i = 0; i < lpCurve->cpfx; ++i)
817 p.setValues(lpCurve->apfx[i].x.value, lpCurve->apfx[i].y.value);
818 p *= scale;
819 p -= offset;
820 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
823 else if (lpCurve->wType == TT_PRIM_QSPLINE)
825 // All points apart from the last point of off the curve quadratric
826 // Bezier spline control points. The last point is on the curve.
827 // Between two consecutive control points, we have to insert a point
828 // that is on the curve. This point lies directly between the two control
829 // points.
830 short x1, x2, y1, y2;
831 for (i = 0; i < lpCurve->cpfx; ++i)
833 x2 = lpCurve->apfx[i].x.value;
834 y2 = lpCurve->apfx[i].y.value;
835 if (i >= lpCurve->cpfx - 1)
837 p.setValues(x2, y2);
838 p *= scale;
839 p -= offset;
840 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
841 break;
843 if (i > 0)
845 x1 = (x1 + x2) >> 1;
846 y1 = (y1 + y2) >> 1;
847 p.setValues(x1, y1);
848 p *= scale;
849 p -= offset;
850 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
852 p.setValues(x2, y2);
853 p *= scale;
854 p -= offset;
855 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_QUAD));
856 x1 = x2;
857 y1 = y2;
860 else if (lpCurve->wType == TT_PRIM_CSPLINE)
862 // TODO: Did not find any font until now that contains cubic
863 // splines, so this code is untested -pdaehne
864 for (i = 0; i < lpCurve->cpfx; ++i)
866 p.setValues(lpCurve->apfx[i].x.value, lpCurve->apfx[i].y.value);
867 p *= scale;
868 p -= offset;
869 if (i >= lpCurve->cpfx - 1)
870 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
871 else
872 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
875 else
876 // Oops! A POLYCURVE format we don't understand.
877 ; // error, error, error
879 // Keep the end point
880 endPoint = &(lpCurve->apfx[lpCurve->cpfx - 1]);
882 // Move on to next curve in the contour.
883 lpCurve = (LPTTPOLYCURVE)&(lpCurve->apfx[lpCurve->cpfx]);
886 // Check if the contour is valid, i.e. if it has more than two points.
887 // When not, we simply delete the contour.
888 if (_outline.back().size() < 3)
889 _outline.erase(_outline.end() - 1);
890 else
891 // Add points to close the contour.
892 // All contours are implied closed by TrueType definition.
893 // Depending on the specific font and glyph being used, these
894 // may not always be needed.
895 if ((startPoint.x.value != endPoint->x.value) || (startPoint.y.value != endPoint->y.value))
897 p.setValues(startPoint.x.value, startPoint.y.value);
898 p *= scale;
899 p -= offset;
900 _outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
903 else
904 // Bad, bail, must have a bogus buffer.
905 break; // error, error, error
907 // Move on to next Contour.
908 // Its header starts immediate after this contour
909 lpHeader = (LPTTPOLYGONHEADER)(((LPSTR)lpHeader) + lpHeader->cb);
914 //----------------------------------------------------------------------
915 // Destructor
916 // Author: pdaehne
917 //----------------------------------------------------------------------
918 TextWIN32VectorGlyph::~TextWIN32VectorGlyph() {}
921 //----------------------------------------------------------------------
922 // Constructor
923 // Author: pdaehne
924 //----------------------------------------------------------------------
925 TextWIN32PixmapFace::TextWIN32PixmapFace(TextWIN32Backend *backend, HFONT hHoriFont, HFONT hVertFont, UInt32 size)
926 : TextPixmapFace(), _backend(backend), _hHoriFont(hHoriFont), _hVertFont(hVertFont)
928 // Get information about the font
929 getFontInfo(_backend->_hDC, _hHoriFont, _family, _style,
930 _horiAscent, _horiDescent);
932 // Set the size
933 _size = size;
935 // Determine vertical ascent and descent
936 _vertAscent = -static_cast<Real32>(_size) / 2.f;
937 _vertDescent = static_cast<Real32>(_size) / 2.f;
941 //----------------------------------------------------------------------
942 // Destructor
943 // Author: pdaehne
944 //----------------------------------------------------------------------
945 TextWIN32PixmapFace::~TextWIN32PixmapFace()
947 // Destroy the font objects
948 DeleteObject(_hHoriFont);
949 DeleteObject(_hVertFont);
953 //----------------------------------------------------------------------
954 // Lays out one line of text
955 // Author: pdaehne
956 //----------------------------------------------------------------------
957 void TextWIN32PixmapFace::layout(const wstring &text, const TextLayoutParam &param,
958 TextLayoutResult &layoutResult)
960 // Initialize return values
961 layoutResult.clear();
962 if (param.horizontal == true)
963 layoutResult.textBounds[1] = _horiAscent - _horiDescent;
964 else
965 layoutResult.textBounds[0] = _vertDescent - _vertAscent;
966 layoutResult.lineBounds.push_back(layoutResult.textBounds);
968 // Convert the unicode string to utf16
969 vector<WCHAR> utf16Text;
970 convertUnicodeToUTF16(text, utf16Text);
971 vector<WCHAR>::size_type len = utf16Text.size();
972 if (len == 0)
973 return;
975 // Select the font into the device context
976 HGDIOBJ oldFont;
977 if (param.horizontal == true)
978 oldFont = SelectObject(_backend->_hDC, _hHoriFont);
979 else
980 oldFont = SelectObject(_backend->_hDC, _hVertFont);
982 GCP_RESULTSW results;
983 ZeroMemory(&results, sizeof(results));
984 results.lStructSize = sizeof(results);
985 results.lpDx = new int[len];
986 results.lpGlyphs = new WCHAR[len];
987 results.lpGlyphs[0] = 0; // needed by GCP_LIGATE
988 results.nGlyphs = UInt32(len);
989 DWORD dwFlags = GCP_GLYPHSHAPE | GCP_LIGATE | GCP_REORDER | GCP_USEKERNING;
990 int nMaxExtent = 0;
991 Real32 length = param.getLength(0);
992 if (length > 0)
994 dwFlags |= GCP_JUSTIFY | GCP_KASHIDA | GCP_MAXEXTENT;
995 nMaxExtent = length;
997 DWORD result = GetCharacterPlacementW(_backend->_hDC, &(utf16Text[0]), UInt32(len), nMaxExtent, &results, dwFlags);
998 if (result != 0)
1000 layoutResult.indices.reserve(results.nGlyphs);
1001 layoutResult.positions.reserve(results.nGlyphs);
1002 UINT j;
1003 Vec2f currPos;
1004 for (j = 0; j < results.nGlyphs; ++j)
1006 // Get glyph
1007 const TextGlyph &glyph = getGlyph(results.lpGlyphs[j]);
1009 // Calculate position
1010 Vec2f pos;
1011 if (param.horizontal == true)
1013 pos[0] = currPos.x() + glyph.getHoriBearingX();
1014 pos[1] = currPos.y() + glyph.getHoriBearingY();
1015 currPos[0] += results.lpDx[j];
1017 else
1019 pos[0] = currPos.x() + glyph.getVertBearingX();
1020 pos[1] = currPos.y() + glyph.getVertBearingY();
1021 currPos[1] -= results.lpDx[j];
1023 layoutResult.indices.push_back(results.lpGlyphs[j]);
1024 layoutResult.positions.push_back(pos);
1027 // Adjust the origin depending on the major and the minor alignment
1028 adjustLineOrigin(param, currPos, layoutResult);
1030 // Determine text bounds / line bounds
1031 if (param.horizontal == true)
1032 layoutResult.textBounds[0] = osgAbs(currPos.x());
1033 else
1034 layoutResult.textBounds[1] = osgAbs(currPos.y());
1035 OSG_ASSERT(layoutResult.lineBounds.empty() == false);
1036 layoutResult.lineBounds.front() = layoutResult.textBounds;
1038 delete [] results.lpDx;
1039 delete [] results.lpGlyphs;
1041 // Unselect the font
1042 SelectObject(_backend->_hDC, oldFont);
1046 //----------------------------------------------------------------------
1047 // Creates a new Glyph object
1048 // Author: pdaehne
1049 //----------------------------------------------------------------------
1050 unique_ptr<TextPixmapGlyph> TextWIN32PixmapFace::createGlyph(TextGlyph::Index glyphIndex)
1052 // We cannot create glyphs for invalid glyph indices
1053 if (glyphIndex == TextGlyph::INVALID_INDEX)
1054 return unique_ptr<TextPixmapGlyph>();
1056 // Select the vertical font into the device context
1057 HGDIOBJ oldFont = SelectObject(_backend->_hDC, _hVertFont);
1059 // Get the vertical metrics
1060 GLYPHMETRICS vpgm;
1061 MAT2 mat2 = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
1062 DWORD size = GetGlyphOutlineW(_backend->_hDC, glyphIndex, GGO_METRICS | GGO_GLYPH_INDEX,
1063 &vpgm, 0, 0, &mat2);
1064 if (size == GDI_ERROR)
1066 SelectObject(_backend->_hDC, oldFont);
1067 return unique_ptr<TextPixmapGlyph>();
1070 // Select the horizontal font into the device context
1071 SelectObject(_backend->_hDC, _hHoriFont);
1073 GLYPHMETRICS hpgm;
1074 size = GetGlyphOutlineW(_backend->_hDC, glyphIndex, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX,
1075 &hpgm, 0, 0, &mat2);
1076 if (size == GDI_ERROR)
1078 SelectObject(_backend->_hDC, oldFont);
1079 return unique_ptr<TextPixmapGlyph>();
1081 UInt8 *buffer;
1082 if (size == 0)
1083 buffer = 0;
1084 else
1086 // Get the pixmap
1087 buffer = new UInt8[size];
1088 size = GetGlyphOutlineW(_backend->_hDC, glyphIndex, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX,
1089 &hpgm, size, buffer, &mat2);
1090 if (size == GDI_ERROR)
1092 delete [] buffer;
1093 SelectObject(_backend->_hDC, oldFont);
1094 return unique_ptr<TextPixmapGlyph>();
1097 // The gray values in the buffer are between 0 and 64, inclusively.
1098 // So we have to scale them
1099 DWORD i;
1100 UInt8 *ptr = buffer;
1101 for (i = size; i > 0; --i)
1103 *ptr = *ptr >= 64 ? 255 : *ptr << 2;
1104 ++ptr;
1107 SelectObject(_backend->_hDC, oldFont);
1109 // Create and return the new glyph object
1110 return unique_ptr<TextPixmapGlyph>(new TextWIN32PixmapGlyph(glyphIndex, hpgm, vpgm, buffer));
1114 //----------------------------------------------------------------------
1115 // Constructor
1116 // Author: pdaehne
1117 //----------------------------------------------------------------------
1118 TextWIN32PixmapGlyph::TextWIN32PixmapGlyph(Index glyphIndex, const GLYPHMETRICS &hpgm,
1119 const GLYPHMETRICS &vpgm, UInt8 *pixmap)
1120 : TextPixmapGlyph()
1122 _glyphIndex = glyphIndex;
1123 _width = hpgm.gmBlackBoxX;
1124 _pitch = (hpgm.gmBlackBoxX + 3) & ~3;
1125 _height = hpgm.gmBlackBoxY;
1126 _pixmap = pixmap;
1127 flipPixmap();
1129 // Determine horizontal glyph metrics
1130 _horiAdvance = hpgm.gmCellIncX;
1131 _horiBearingX = hpgm.gmptGlyphOrigin.x;
1132 _horiBearingY = hpgm.gmptGlyphOrigin.y;
1134 // Determine vertical glyph metrics
1135 // Hmmm, there is no useful information here for vertical layout -
1136 // the values provided are just the same as for horizontal layout.
1137 // So we have to guess resonable values -pdaehne
1138 //_vertAdvance = vpgm.gmCellIncY;
1139 //_vertBearingX = vpgm.gmptGlyphOrigin.x;
1140 //_vertBearingY = vpgm.gmptGlyphOrigin.y;
1141 _vertAdvance = -static_cast<Int32>(_height);
1142 _vertBearingX = -static_cast<Int32>(_width >> 1);
1143 _vertBearingY = 0;
1147 //----------------------------------------------------------------------
1148 // Destructor
1149 // Author: pdaehne
1150 //----------------------------------------------------------------------
1151 TextWIN32PixmapGlyph::~TextWIN32PixmapGlyph() {}
1154 //----------------------------------------------------------------------
1155 // Constructor
1156 // Author: pdaehne
1157 //----------------------------------------------------------------------
1158 TextWIN32TXFFace::TextWIN32TXFFace(const TextWIN32Backend *backend, HFONT hHoriFont, HFONT hVertFont, const TextTXFParam &param)
1159 : TextTXFFace()
1161 // Get information about the font
1162 getFontInfo(backend->_hDC, hHoriFont, _family, _style,
1163 _horiAscent, _horiDescent);
1165 // Set the parameters
1166 _param = param;
1168 // Determine the scale factor & adjust ascent and descent
1169 _scale = 1.f / (_horiAscent - _horiDescent);
1170 _horiAscent *= _scale;
1171 _horiDescent *= _scale;
1173 // Determine vertical ascent and descent
1174 _vertAscent = -0.5f;
1175 _vertDescent = 0.5f;
1177 // Convert the unicode string to utf16
1178 vector<WCHAR> utf16Text;
1179 convertUnicodeToUTF16(param.getCharacters(), utf16Text);
1180 vector<WCHAR>::size_type len = utf16Text.size();
1181 if (len == 0)
1183 DeleteObject(hHoriFont);
1184 DeleteObject(hVertFont);
1185 return;
1188 // Select the font into the device context
1189 HGDIOBJ oldFont = SelectObject(backend->_hDC, hHoriFont);
1191 GCP_RESULTSW results;
1192 ZeroMemory(&results, sizeof(results));
1193 results.lStructSize = sizeof(results);
1194 results.lpGlyphs = new WCHAR[len];
1195 results.nGlyphs = UInt32(len);
1196 DWORD result = GetCharacterPlacementW(backend->_hDC, &(utf16Text[0]), UInt32(len), 0, &results, 0);
1197 if (result == 0)
1199 delete [] results.lpGlyphs;
1200 SelectObject(backend->_hDC, oldFont);
1201 DeleteObject(hHoriFont);
1202 DeleteObject(hVertFont);
1203 return;
1206 // Create all glyphs
1207 OSG_ASSERT(results.nGlyphs == param.getCharacters().length());
1208 UINT j;
1209 for (j = 0; j < results.nGlyphs; ++j)
1211 // Select the vertical font into the device context
1212 SelectObject(backend->_hDC, hVertFont);
1214 // Get the vertical metrics
1215 GLYPHMETRICS vpgm;
1216 MAT2 mat2 = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
1217 DWORD size = GetGlyphOutlineW(backend->_hDC, results.lpGlyphs[j], GGO_METRICS | GGO_GLYPH_INDEX,
1218 &vpgm, 0, 0, &mat2);
1219 if (size == GDI_ERROR)
1220 continue;
1222 // Select the horizontal font into the device context
1223 SelectObject(backend->_hDC, hHoriFont);
1225 // Get the horizontal metrics
1226 GLYPHMETRICS hpgm;
1227 // Using GGO_METRICS gives a to small value for the width of the glyph...
1228 size = GetGlyphOutlineW(backend->_hDC, results.lpGlyphs[j], /*GGO_METRICS*/GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX,
1229 &hpgm, 0, 0, &mat2);
1230 if (size == GDI_ERROR)
1231 continue;
1233 _glyphMap.insert(GlyphMap::value_type(param.getCharacters()[j], new TextWIN32TXFGlyph(param.getCharacters()[j], this, _scale, hpgm, vpgm)));
1236 // Calculate the positions of the glyphs on the texture
1237 prepareTexture(param);
1238 OSG_ASSERT(_texture != NULL);
1239 OSG_ASSERT(_texture->getSize() == static_cast<UInt32>(_texture->getWidth() * _texture->getHeight()));
1241 // Create the texture
1242 SelectObject(backend->_hDC, hHoriFont);
1243 vector<unsigned char> buffer;
1245 for (j = 0; j < results.nGlyphs; ++j)
1247 // Get the pixmap
1248 GLYPHMETRICS hpgm;
1249 MAT2 mat2 = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
1250 DWORD size = GetGlyphOutlineW(backend->_hDC, results.lpGlyphs[j], GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX,
1251 &hpgm, 0, 0, &mat2);
1252 if ((size == GDI_ERROR) || (size == 0))
1253 continue;
1254 buffer.resize(size);
1255 size = GetGlyphOutlineW(backend->_hDC, results.lpGlyphs[j], GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX,
1256 &hpgm, size, &(buffer[0]), &mat2);
1257 if (size == GDI_ERROR)
1258 continue;
1260 // Try to find the glyph in the glyphmap
1261 GlyphMap::iterator gIt = _glyphMap.find(param.getCharacters()[j]);
1262 if (gIt == _glyphMap.end())
1263 continue;
1264 OSG_ASSERT(gIt->second != 0);
1265 TextTXFGlyph *glyph = gIt->second;
1267 // Put the glyph pixmap into the texture
1268 unsigned char *src = &(buffer[0]);
1269 int bpl = (hpgm.gmBlackBoxX + 3) & ~3;
1270 src += bpl * (hpgm.gmBlackBoxY - 1);
1271 unsigned char *src2;
1272 UInt8 *dst = _texture->editData() + glyph->getX() + glyph->getY() * _texture->getWidth();
1273 UInt32 dstPitch = _texture->getWidth() - glyph->getPixmapWidth();
1274 UInt32 x, y;
1275 for (y = 0; y < glyph->getPixmapHeight(); ++y)
1277 src2 = src;
1278 for (x = 0; x < glyph->getPixmapWidth(); ++x)
1280 // The gray values in the buffer are between 0 and 64, inclusively.
1281 // So we have to scale them
1282 *dst++ = *src2 >= 64 ? 255 : *src2 << 2;
1283 ++src2;
1285 src -= bpl;
1286 dst += dstPitch;
1291 delete [] results.lpGlyphs;
1293 // Unselect the font
1294 SelectObject(backend->_hDC, oldFont);
1296 // Cleanup
1297 DeleteObject(hHoriFont);
1298 DeleteObject(hVertFont);
1302 //----------------------------------------------------------------------
1303 // Destructor
1304 // Author: pdaehne
1305 //----------------------------------------------------------------------
1306 TextWIN32TXFFace::~TextWIN32TXFFace() {}
1309 //----------------------------------------------------------------------
1310 // Constructor
1311 // Author: pdaehne
1312 //----------------------------------------------------------------------
1313 TextWIN32TXFGlyph::TextWIN32TXFGlyph(Index glyphIndex, TextWIN32TXFFace *face, Real32 scale,
1314 const GLYPHMETRICS &hpgm, const GLYPHMETRICS &vpgm)
1315 : TextTXFGlyph()
1317 _glyphIndex = glyphIndex;
1318 _scale = scale;
1319 _width = hpgm.gmBlackBoxX;
1320 _height = hpgm.gmBlackBoxY;
1322 // Determine horizontal glyph metrics
1323 _horiAdvance = static_cast<Real32>(hpgm.gmCellIncX) * _scale;
1324 _horiBearingX = hpgm.gmptGlyphOrigin.x;
1325 _horiBearingY = hpgm.gmptGlyphOrigin.y;
1327 // Determine vertical glyph metrics
1328 // Hmmm, there is no useful information here for vertical layout -
1329 // the values provided are just the same as for horizontal layout.
1330 // So we have to guess resonable values -pdaehne
1331 //_vertAdvance = static_cast<Real32>(vpgm.gmCellIncY) * _scale;
1332 //_vertBearingX = vpgm.gmptGlyphOrigin.x;
1333 //_vertBearingY = vpgm.gmptGlyphOrigin.y;
1334 _vertBearingX = -static_cast<Int32>(_width >> 1);
1335 if (glyphIndex == 32)
1337 _vertBearingY = -_horiBearingX;
1338 _vertAdvance = -_horiAdvance;
1340 else
1342 _vertBearingY = static_cast<Int32>(-(face->getHoriAscent() - face->getHoriDescent()) / _scale / 20.f);
1343 if (_vertBearingY > -1)
1344 _vertBearingY = -1;
1345 Real32 vertAdvanceOffset = static_cast<Real32>(_vertBearingY) * 2.f * _scale;
1346 _vertAdvance = -static_cast<Real32>(_height) * _scale + vertAdvanceOffset;
1351 //----------------------------------------------------------------------
1352 // Destructor
1353 // Author: pdaehne
1354 //----------------------------------------------------------------------
1355 TextWIN32TXFGlyph::~TextWIN32TXFGlyph() {}
1358 OSG_END_NAMESPACE
1361 #endif // _WIN32