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