1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 #include "OSGTextWIN32Backend.h"
40 #include "OSGBaseTypes.h"
43 #if defined(_WIN32) || defined(OSG_DO_DOC)
47 # pragma warning (disable: 4786)
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"
68 //----------------------------------------------------------------------
69 // WIN32 specific implementation of the TextVectorFace class
71 //----------------------------------------------------------------------
76 class TextWIN32VectorFace
: public TextVectorFace
81 TextWIN32VectorFace(TextWIN32Backend
*backend
, HFONT hHoriFont
, HFONT hVertFont
);
84 virtual ~TextWIN32VectorFace();
86 // Lays out one line of text
87 virtual void layout(const wstring
&text
, const TextLayoutParam
¶m
,
88 TextLayoutResult
&layoutResult
);
92 // Creates a new Glyph object
93 virtual unique_ptr
<TextVectorGlyph
> createGlyph(TextGlyph::Index glyphIndex
);
97 // The backend that created the face
98 TextWIN32Backend
*_backend
;
100 // Font handle for horizontal layout
103 // Font handle for vertical layout
108 //----------------------------------------------------------------------
109 // WIN32 specific implementation of the TextVectorGlyph class
111 //----------------------------------------------------------------------
116 class TextWIN32VectorGlyph
: public TextVectorGlyph
121 TextWIN32VectorGlyph(Index glyphIndex
, Real32 scale
,
122 const GLYPHMETRICS
&hpgm
, const GLYPHMETRICS
&vhpgm
,
123 LPTTPOLYGONHEADER lpHeader
, DWORD size
);
126 virtual ~TextWIN32VectorGlyph();
130 //----------------------------------------------------------------------
131 // WIN32 specific implementation of the TextPixmapFace class
133 //----------------------------------------------------------------------
138 class TextWIN32PixmapFace
: public TextPixmapFace
143 TextWIN32PixmapFace(TextWIN32Backend
*backend
, HFONT hHoriFont
, HFONT hVertFont
, UInt32 size
);
146 virtual ~TextWIN32PixmapFace();
148 // Lays out one line of text
149 virtual void layout(const wstring
&text
, const TextLayoutParam
¶m
,
150 TextLayoutResult
&layoutResult
);
154 // Creates a new Glyph object
155 virtual unique_ptr
<TextPixmapGlyph
> createGlyph(TextGlyph::Index glyphIndex
);
159 // The backend that created the face
160 TextWIN32Backend
*_backend
;
162 // Font handle for horizontal layout
165 // Font handle for vertical layout
170 //----------------------------------------------------------------------
171 // WIN32 specific implementation of the TextPixmapGlyph class
173 //----------------------------------------------------------------------
178 class TextWIN32PixmapGlyph
: public TextPixmapGlyph
183 TextWIN32PixmapGlyph(Index glyphIndex
, const GLYPHMETRICS
&hpgm
,
184 const GLYPHMETRICS
&vpgm
, UInt8
*pixmap
);
187 virtual ~TextWIN32PixmapGlyph();
191 //----------------------------------------------------------------------
192 // WIN32 specific implementation of the TextTXFFace class
194 //----------------------------------------------------------------------
199 class TextWIN32TXFFace
: public TextTXFFace
204 TextWIN32TXFFace(const TextWIN32Backend
*backend
, HFONT hHoriFont
, HFONT hVertFont
,
205 const TextTXFParam
¶m
);
208 virtual ~TextWIN32TXFFace();
212 //----------------------------------------------------------------------
213 // WIN32 specific implementation of the TextTXFGlyph class
215 //----------------------------------------------------------------------
220 class TextWIN32TXFGlyph
: public TextTXFGlyph
225 TextWIN32TXFGlyph(Index glyphIndex
, TextWIN32TXFFace
*face
, Real32 scale
,
226 const GLYPHMETRICS
&hpgm
, const GLYPHMETRICS
&vpgm
);
229 virtual ~TextWIN32TXFGlyph();
233 //----------------------------------------------------------------------
236 //----------------------------------------------------------------------
237 TextWIN32Backend::TextWIN32Backend()
238 : TextBackend(), _hDC(0)
240 // Create device context
241 _hDC
= CreateDC("DISPLAY", 0, 0, 0);
244 SWARNING
<< "TextWIN32Backend: Failed to create device context."
249 SetGraphicsMode(_hDC
, GM_ADVANCED
);
253 //----------------------------------------------------------------------
256 //----------------------------------------------------------------------
257 TextWIN32Backend::~TextWIN32Backend()
259 // Destroy device context
264 //----------------------------------------------------------------------
265 // Helper struct used by enumFamCallBack
267 //----------------------------------------------------------------------
280 //----------------------------------------------------------------------
281 // Callback that gets called by Windows to enumerate fonts
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)
291 // Fill enumData structure
292 EnumData
*enumData
= reinterpret_cast<EnumData
*>(lParam
);
293 enumData
->fullname
= (const char *)lpelf
->elfFullName
;
294 enumData
->emSize
= lpntm
->ntmSizeEM
;
301 //----------------------------------------------------------------------
302 // Creates horizontal and vertical fonts from given fontname,
305 //----------------------------------------------------------------------
306 void TextWIN32Backend::createFonts(const string
&family
, UInt32 size
, TextFace::Style style
,
307 HFONT
&hHoriFont
, HFONT
&hVertFont
)
310 hHoriFont
= hVertFont
= 0;
312 // Handle generic family names
314 if (family
== "SERIF")
315 f
= "Times New Roman";
316 else if (family
== "SANS")
318 else if (family
== "TYPEWRITER")
325 // Grrr - this is only necessary to get the EM size -pdaehne
327 EnumFontFamilies(_hDC
, (LPCTSTR
)(f
.c_str()), (FONTENUMPROC
)enumFamCallBack
,
329 if (enumData
.fullname
.empty() == true)
331 size
= -enumData
.emSize
;
340 FWARNING(("Invalid font style parameter.\n"));
341 // intentionally fall through
342 case TextFace::STYLE_PLAIN
:
346 case TextFace::STYLE_BOLD
:
350 case TextFace::STYLE_ITALIC
:
354 case TextFace::STYLE_BOLDITALIC
:
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
,
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
,
374 //----------------------------------------------------------------------
375 // Creates a new vector face
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
);
388 // Create the new face object
389 retVal
= new TextWIN32VectorFace(this, hHoriFont
, hVertFont
);
396 //----------------------------------------------------------------------
397 // Creates a new pixmap face
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
);
410 // Create the new face object
411 retVal
= new TextWIN32PixmapFace(this, hHoriFont
, hVertFont
, size
);
418 //----------------------------------------------------------------------
419 // Creates a new TXF face
421 //----------------------------------------------------------------------
422 TextTXFFaceTransitPtr
TextWIN32Backend::createTXFFace(
423 const string
&family
, TextFace::Style style
, const TextTXFParam
¶m
)
425 TextTXFFaceTransitPtr retVal
;
427 // Try to create the font handles
428 HFONT hHoriFont
, hVertFont
;
429 createFonts(family
, param
.size
, style
, hHoriFont
, hVertFont
);
432 // Create the new face object
433 retVal
= new TextWIN32TXFFace(this, hHoriFont
, hVertFont
, param
);
440 //----------------------------------------------------------------------
441 // Callback that gets called by Windows to enumerate fonts
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)
451 // Fill enumData structure
452 set
<string
> *familySet
= reinterpret_cast<set
<string
>*>(lParam
);
453 familySet
->insert(lpelf
->elfLogFont
.lfFaceName
);
455 // Continue enumeration
460 //----------------------------------------------------------------------
461 // Returns the names of all font families available
463 //----------------------------------------------------------------------
464 void TextWIN32Backend::getFontFamilies(vector
<string
> &families
)
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
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
496 BOOL result
= GetTextMetrics(hDC
, &tm
);
497 SelectObject(hDC
, oldFont
);
501 // Determine the style
502 if (tm
.tmWeight
> (FW_NORMAL
+ FW_BOLD
) / 2)
503 style
= tm
.tmItalic
!= 0 ? TextFace::STYLE_BOLDITALIC
: TextFace::STYLE_BOLD
;
505 style
= tm
.tmItalic
!= 0 ? TextFace::STYLE_ITALIC
: TextFace::STYLE_PLAIN
;
508 ascent
= static_cast<Real32
>(tm
.tmAscent
);
511 descent
= static_cast<Real32
>(-tm
.tmDescent
);
515 //----------------------------------------------------------------------
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
538 //----------------------------------------------------------------------
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
554 //----------------------------------------------------------------------
555 static void convertUnicodeToUTF16(const wstring
&text
, vector
<WCHAR
> &utf16Text
)
557 wstring::size_type i
, textTotalLength
= text
.length();
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
578 //----------------------------------------------------------------------
579 void TextWIN32VectorFace::layout(const wstring
&text
, const TextLayoutParam
¶m
,
580 TextLayoutResult
&layoutResult
)
582 // Initialize return values
583 layoutResult
.clear();
584 if (param
.horizontal
== true)
585 layoutResult
.textBounds
[1] = _horiAscent
- _horiDescent
;
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();
597 // Select the font into the device context
599 if (param
.horizontal
== true)
600 oldFont
= SelectObject(_backend
->_hDC
, _hHoriFont
);
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
;
613 Real32 length
= param
.getLength(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
);
622 layoutResult
.indices
.reserve(results
.nGlyphs
);
623 layoutResult
.positions
.reserve(results
.nGlyphs
);
626 for (j
= 0; j
< results
.nGlyphs
; ++j
)
629 const TextGlyph
&glyph
= getGlyph(results
.lpGlyphs
[j
]);
631 // Calculate position
633 if (param
.horizontal
== true)
636 pos
[0] += glyph
.getHoriBearingX();
637 pos
[1] += glyph
.getHoriBearingY();
638 currPos
[0] += results
.lpDx
[j
] * _scale
;
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());
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
;
666 SelectObject(_backend
->_hDC
, oldFont
);
670 //----------------------------------------------------------------------
671 // Creates a new Glyph object
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
685 MAT2 mat2
= { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
686 DWORD size
= GetGlyphOutlineW(_backend
->_hDC
, glyphIndex
, GGO_METRICS
| GGO_GLYPH_INDEX
,
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
);
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
);
709 SelectObject(_backend
->_hDC
, oldFont
);
711 if (size
== GDI_ERROR
)
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
));
725 //----------------------------------------------------------------------
728 //----------------------------------------------------------------------
729 TextWIN32VectorGlyph::TextWIN32VectorGlyph(Index glyphIndex
, Real32 scale
,
730 const GLYPHMETRICS
&hpgm
,
731 const GLYPHMETRICS
&vpgm
,
732 LPTTPOLYGONHEADER lpHeader
,
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
;
756 Vec2f
offset(_horiBearingX
, _horiBearingY
), p
;
758 // The following algorithm has been taken from MSDN article Q243285
759 // "HOWTO: Draw TrueType Glyph Outlines" - pdaehne
762 LPTTPOLYGONHEADER lpStart
; // the start of the buffer
763 LPTTPOLYCURVE lpCurve
; // the current curve of a contour
764 POINTFX
*endPoint
= 0;
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
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
);
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
);
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
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)
840 _outline
.back().push_back(TextVectorGlyph::Point(p
, TextVectorGlyph::Point::PT_ON
));
850 _outline
.back().push_back(TextVectorGlyph::Point(p
, TextVectorGlyph::Point::PT_ON
));
855 _outline
.back().push_back(TextVectorGlyph::Point(p
, TextVectorGlyph::Point::PT_QUAD
));
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
);
869 if (i
>= lpCurve
->cpfx
- 1)
870 _outline
.back().push_back(TextVectorGlyph::Point(p
, TextVectorGlyph::Point::PT_ON
));
872 _outline
.back().push_back(TextVectorGlyph::Point(p
, TextVectorGlyph::Point::PT_CUBIC
));
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);
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
);
900 _outline
.back().push_back(TextVectorGlyph::Point(p
, TextVectorGlyph::Point::PT_ON
));
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 //----------------------------------------------------------------------
917 //----------------------------------------------------------------------
918 TextWIN32VectorGlyph::~TextWIN32VectorGlyph() {}
921 //----------------------------------------------------------------------
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
);
935 // Determine vertical ascent and descent
936 _vertAscent
= -static_cast<Real32
>(_size
) / 2.f
;
937 _vertDescent
= static_cast<Real32
>(_size
) / 2.f
;
941 //----------------------------------------------------------------------
944 //----------------------------------------------------------------------
945 TextWIN32PixmapFace::~TextWIN32PixmapFace()
947 // Destroy the font objects
948 DeleteObject(_hHoriFont
);
949 DeleteObject(_hVertFont
);
953 //----------------------------------------------------------------------
954 // Lays out one line of text
956 //----------------------------------------------------------------------
957 void TextWIN32PixmapFace::layout(const wstring
&text
, const TextLayoutParam
¶m
,
958 TextLayoutResult
&layoutResult
)
960 // Initialize return values
961 layoutResult
.clear();
962 if (param
.horizontal
== true)
963 layoutResult
.textBounds
[1] = _horiAscent
- _horiDescent
;
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();
975 // Select the font into the device context
977 if (param
.horizontal
== true)
978 oldFont
= SelectObject(_backend
->_hDC
, _hHoriFont
);
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
;
991 Real32 length
= param
.getLength(0);
994 dwFlags
|= GCP_JUSTIFY
| GCP_KASHIDA
| GCP_MAXEXTENT
;
997 DWORD result
= GetCharacterPlacementW(_backend
->_hDC
, &(utf16Text
[0]), UInt32(len
), nMaxExtent
, &results
, dwFlags
);
1000 layoutResult
.indices
.reserve(results
.nGlyphs
);
1001 layoutResult
.positions
.reserve(results
.nGlyphs
);
1004 for (j
= 0; j
< results
.nGlyphs
; ++j
)
1007 const TextGlyph
&glyph
= getGlyph(results
.lpGlyphs
[j
]);
1009 // Calculate position
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
];
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());
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
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
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
);
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
>();
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
)
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
1100 UInt8
*ptr
= buffer
;
1101 for (i
= size
; i
> 0; --i
)
1103 *ptr
= *ptr
>= 64 ? 255 : *ptr
<< 2;
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 //----------------------------------------------------------------------
1117 //----------------------------------------------------------------------
1118 TextWIN32PixmapGlyph::TextWIN32PixmapGlyph(Index glyphIndex
, const GLYPHMETRICS
&hpgm
,
1119 const GLYPHMETRICS
&vpgm
, UInt8
*pixmap
)
1122 _glyphIndex
= glyphIndex
;
1123 _width
= hpgm
.gmBlackBoxX
;
1124 _pitch
= (hpgm
.gmBlackBoxX
+ 3) & ~3;
1125 _height
= hpgm
.gmBlackBoxY
;
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);
1147 //----------------------------------------------------------------------
1150 //----------------------------------------------------------------------
1151 TextWIN32PixmapGlyph::~TextWIN32PixmapGlyph() {}
1154 //----------------------------------------------------------------------
1157 //----------------------------------------------------------------------
1158 TextWIN32TXFFace::TextWIN32TXFFace(const TextWIN32Backend
*backend
, HFONT hHoriFont
, HFONT hVertFont
, const TextTXFParam
¶m
)
1161 // Get information about the font
1162 getFontInfo(backend
->_hDC
, hHoriFont
, _family
, _style
,
1163 _horiAscent
, _horiDescent
);
1165 // Set the parameters
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();
1183 DeleteObject(hHoriFont
);
1184 DeleteObject(hVertFont
);
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);
1199 delete [] results
.lpGlyphs
;
1200 SelectObject(backend
->_hDC
, oldFont
);
1201 DeleteObject(hHoriFont
);
1202 DeleteObject(hVertFont
);
1206 // Create all glyphs
1207 OSG_ASSERT(results
.nGlyphs
== param
.getCharacters().length());
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
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
)
1222 // Select the horizontal font into the device context
1223 SelectObject(backend
->_hDC
, hHoriFont
);
1225 // Get the horizontal metrics
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
)
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
)
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))
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
)
1260 // Try to find the glyph in the glyphmap
1261 GlyphMap::iterator gIt
= _glyphMap
.find(param
.getCharacters()[j
]);
1262 if (gIt
== _glyphMap
.end())
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();
1275 for (y
= 0; y
< glyph
->getPixmapHeight(); ++y
)
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;
1291 delete [] results
.lpGlyphs
;
1293 // Unselect the font
1294 SelectObject(backend
->_hDC
, oldFont
);
1297 DeleteObject(hHoriFont
);
1298 DeleteObject(hVertFont
);
1302 //----------------------------------------------------------------------
1305 //----------------------------------------------------------------------
1306 TextWIN32TXFFace::~TextWIN32TXFFace() {}
1309 //----------------------------------------------------------------------
1312 //----------------------------------------------------------------------
1313 TextWIN32TXFGlyph::TextWIN32TXFGlyph(Index glyphIndex
, TextWIN32TXFFace
*face
, Real32 scale
,
1314 const GLYPHMETRICS
&hpgm
, const GLYPHMETRICS
&vpgm
)
1317 _glyphIndex
= glyphIndex
;
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
;
1342 _vertBearingY
= static_cast<Int32
>(-(face
->getHoriAscent() - face
->getHoriDescent()) / _scale
/ 20.f
);
1343 if (_vertBearingY
> -1)
1345 Real32 vertAdvanceOffset
= static_cast<Real32
>(_vertBearingY
) * 2.f
* _scale
;
1346 _vertAdvance
= -static_cast<Real32
>(_height
) * _scale
+ vertAdvanceOffset
;
1351 //----------------------------------------------------------------------
1354 //----------------------------------------------------------------------
1355 TextWIN32TXFGlyph::~TextWIN32TXFGlyph() {}