1 //////////////////////////////////////////////////////////////////////////////
2 // Name: SVGCanvasTextCairo.h
3 // Purpose: Cairo canvas text
4 // Author: Alex Thuering
5 // Created: 2011/06/23
6 // RCS-ID: $Id: SVGCanvasTextCairo.cpp,v 1.13 2014/06/16 19:40:46 ntalex Exp $
7 // Copyright: (c) 2011 Alex Thuering
8 // Licence: wxWindows licence
9 //////////////////////////////////////////////////////////////////////////////
10
11 #include "SVGCanvasTextCairo.h"
12 #include "SVGCanvasPathCairo.h"
13 #include <wx/log.h>
14 #include <wx/font.h>
15 #include <wx/tokenzr.h>
16 #include <cairo/cairo.h>
17 #if defined(__WXMSW__)
18 #include <cairo/cairo-win32.h>
19 #elif defined(__WXMAC__)
20 #include <cairo/cairo-quartz.h>
21 #else
22 #include <pango/pangocairo.h>
23 #include <glib-object.h>
24 #endif
25
wxSVGCanvasTextCairo(wxSVGCanvas * canvas)26 wxSVGCanvasTextCairo::wxSVGCanvasTextCairo(wxSVGCanvas* canvas): wxSVGCanvasText(canvas) {
27 }
28
~wxSVGCanvasTextCairo()29 wxSVGCanvasTextCairo::~wxSVGCanvasTextCairo() {
30 }
31
InitText(const wxString & text,const wxCSSStyleDeclaration & style,wxSVGMatrix * matrix)32 void wxSVGCanvasTextCairo::InitText(const wxString& text, const wxCSSStyleDeclaration& style, wxSVGMatrix* matrix) {
33 BeginChar(matrix);
34
35 // create path from text
36 cairo_t* cr = ((wxSVGCanvasPathCairo*) m_char->path)->GetCr();
37
38 #if defined(__WXMSW__) || defined(__WXMAC__)
39 int size = (int) style.GetFontSize();
40 int fstyle = style.GetFontStyle() == wxCSS_VALUE_ITALIC ? wxFONTSTYLE_ITALIC
41 : (style.GetFontStyle() == wxCSS_VALUE_OBLIQUE ? wxFONTSTYLE_SLANT : wxFONTSTYLE_NORMAL);
42 wxFontWeight weight = style.GetFontWeight() == wxCSS_VALUE_BOLD ? wxFONTWEIGHT_BOLD
43 : style.GetFontWeight() == wxCSS_VALUE_BOLDER ? wxFONTWEIGHT_MAX
44 : style.GetFontWeight() == wxCSS_VALUE_LIGHTER ? wxFONTWEIGHT_LIGHT : wxFONTWEIGHT_NORMAL;
45 wxFont fnt(size, wxFONTFAMILY_DEFAULT, fstyle, weight, false, style.GetFontFamily());
46 #ifdef __WXMSW__
47 HFONT hfont = (HFONT) fnt.GetResourceHandle();
48 cairo_set_font_face(cr, cairo_win32_font_face_create_for_hfont(hfont));
49 #else
50 CGFontRef cgFont = fnt.OSXGetCGFont();
51 cairo_set_font_face(cr, cairo_quartz_font_face_create_for_cgfont(cgFont));
52 #endif
53 cairo_set_font_size(cr, style.GetFontSize());
54
55 cairo_font_extents_t fextents;
56 cairo_font_extents(cr, &fextents);
57
58 double maxWidth = 0;
59 if (style.GetTextAnchor() == wxCSS_VALUE_MIDDLE || style.GetTextAnchor() == wxCSS_VALUE_END) {
60 wxStringTokenizer tokenzr(text, wxT("\n"));
61 while (tokenzr.HasMoreTokens()) {
62 wxString token = tokenzr.GetNextToken();
63 cairo_text_extents_t extents;
64 cairo_text_extents(cr, (const char*) token.utf8_str(), &extents);
65 if (maxWidth < extents.width)
66 maxWidth = extents.width;
67 }
68 }
69
70 wxStringTokenizer tokenzr(text, wxT("\n"));
71 double x_advance = 0;
72 double width = 0;
73 double height = 0;
74 double y = 0;
75 while (tokenzr.HasMoreTokens()) {
76 wxString token = tokenzr.GetNextToken();
77
78 // get text extents
79 cairo_text_extents_t extents;
80 cairo_text_extents(cr, (const char*) token.utf8_str(), &extents);
81 double x = style.GetTextAnchor() == wxCSS_VALUE_END ? maxWidth - extents.width
82 : style.GetTextAnchor() == wxCSS_VALUE_MIDDLE ? (maxWidth - extents.width) / 2 : 0;
83
84 m_char->path->MoveTo(m_tx + x, m_ty + y);
85 cairo_text_path(cr, (const char*) token.utf8_str());
86
87 if (x_advance < extents.x_advance)
88 x_advance = extents.x_advance;
89 if (width < extents.width)
90 width = extents.width;
91 height += fextents.height;
92 if (tokenzr.HasMoreTokens())
93 y += fextents.height;
94 }
95
96 // set bbox
97 m_char->bbox = wxSVGRect(m_tx, m_ty, width, height);
98
99 // increase current position (m_tx)
100 if (style.GetTextAnchor() == wxCSS_VALUE_MIDDLE || style.GetTextAnchor() == wxCSS_VALUE_END) {
101 wxSVGRect bbox = m_char->path->GetResultBBox(style);
102 m_tx += x_advance > bbox.GetWidth() ? x_advance : bbox.GetWidth();
103 } else
104 m_tx += x_advance;
105 #else
106 PangoLayout* layout = pango_cairo_create_layout(cr);
107 PangoFontDescription* font = pango_font_description_new();
108 pango_font_description_set_family(font, style.GetFontFamily().ToAscii());
109 pango_font_description_set_weight(font, style.GetFontWeight() == wxCSS_VALUE_BOLD ? PANGO_WEIGHT_BOLD
110 : PANGO_WEIGHT_NORMAL);
111 pango_font_description_set_style(font, style.GetFontStyle() == wxCSS_VALUE_ITALIC ? PANGO_STYLE_ITALIC
112 : (style.GetFontStyle() == wxCSS_VALUE_OBLIQUE ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL));
113 pango_font_description_set_absolute_size(font, style.GetFontSize() * PANGO_SCALE);
114
115 PangoContext* ctx = pango_layout_get_context(layout);
116 PangoFont* f = pango_context_load_font(ctx, font);
117 if (f == NULL)
118 pango_font_description_set_style(font, PANGO_STYLE_NORMAL);
119 pango_layout_set_font_description(layout, font);
120
121 if (style.GetTextAnchor() != wxCSS_VALUE_START)
122 pango_layout_set_alignment(layout, style.GetTextAnchor() == wxCSS_VALUE_MIDDLE ? PANGO_ALIGN_CENTER : PANGO_ALIGN_RIGHT);
123 pango_layout_set_text(layout, (const char*) text.utf8_str(), -1);
124
125 int baseline = pango_layout_get_baseline(layout);
126 m_char->path->MoveTo(m_tx, m_ty - ((double)baseline / PANGO_SCALE));
127 pango_cairo_layout_path(cr, layout);
128
129 // set bbox and increase current position (m_tx)
130 int lwidth, lheight;
131 pango_layout_get_size(layout, &lwidth, &lheight);
132 double width = ((double)lwidth / PANGO_SCALE);
133 double height = ((double)lheight / PANGO_SCALE);
134 m_char->bbox = wxSVGRect(m_tx, m_ty, width, height);
135 if (style.GetTextAnchor() == wxCSS_VALUE_MIDDLE || style.GetTextAnchor() == wxCSS_VALUE_END) {
136 wxSVGRect bbox = m_char->path->GetResultBBox(style);
137 m_tx += width > bbox.GetWidth() ? width : bbox.GetWidth();
138 } else
139 m_tx += width;
140
141 g_object_unref(layout);
142 pango_font_description_free(font);
143 #endif
144 }
145