1 /*
2 *
3 * Copyright (C) 2007 Google (Evan Stade)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winnls.h"
26
27 #include "objbase.h"
28
29 #include "gdiplus.h"
30 #include "gdiplus_private.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
34
35 const GpStringFormat default_drawstring_format =
36 {
37 0,
38 LANG_NEUTRAL,
39 LANG_NEUTRAL,
40 StringAlignmentNear,
41 StringTrimmingCharacter,
42 HotkeyPrefixNone,
43 StringAlignmentNear,
44 StringDigitSubstituteUser,
45 0,
46 0.0,
47 NULL,
48 NULL,
49 0,
50 FALSE
51 };
52
53 static GpStringFormat generic_default_format;
54 static GpStringFormat generic_typographic_format;
55
init_generic_string_formats(void)56 void init_generic_string_formats(void)
57 {
58 memcpy(&generic_default_format, &default_drawstring_format, sizeof(generic_default_format));
59
60 memcpy(&generic_typographic_format, &default_drawstring_format, sizeof(generic_typographic_format));
61 generic_typographic_format.attr = StringFormatFlagsNoFitBlackBox | StringFormatFlagsLineLimit |
62 StringFormatFlagsNoClip;
63 generic_typographic_format.trimming = StringTrimmingNone;
64 generic_typographic_format.generic_typographic = TRUE;
65 }
66
free_generic_string_formats(void)67 void free_generic_string_formats(void)
68 {
69 heap_free(generic_default_format.character_ranges);
70 heap_free(generic_default_format.tabs);
71
72 heap_free(generic_typographic_format.character_ranges);
73 heap_free(generic_typographic_format.tabs);
74 }
75
GdipCreateStringFormat(INT attr,LANGID lang,GpStringFormat ** format)76 GpStatus WINGDIPAPI GdipCreateStringFormat(INT attr, LANGID lang,
77 GpStringFormat **format)
78 {
79 TRACE("(%i, %x, %p)\n", attr, lang, format);
80
81 if(!format)
82 return InvalidParameter;
83
84 *format = heap_alloc_zero(sizeof(GpStringFormat));
85 if(!*format) return OutOfMemory;
86
87 (*format)->attr = attr;
88 (*format)->lang = lang;
89 (*format)->digitlang = LANG_NEUTRAL;
90 (*format)->trimming = StringTrimmingCharacter;
91 (*format)->digitsub = StringDigitSubstituteUser;
92 (*format)->character_ranges = NULL;
93 (*format)->range_count = 0;
94 (*format)->generic_typographic = FALSE;
95 /* tabstops */
96 (*format)->tabcount = 0;
97 (*format)->firsttab = 0.0;
98 (*format)->tabs = NULL;
99
100 TRACE("<-- %p\n", *format);
101
102 return Ok;
103 }
104
GdipDeleteStringFormat(GpStringFormat * format)105 GpStatus WINGDIPAPI GdipDeleteStringFormat(GpStringFormat *format)
106 {
107 if(!format)
108 return InvalidParameter;
109
110 if (format == &generic_default_format || format == &generic_typographic_format)
111 return Ok;
112
113 heap_free(format->character_ranges);
114 heap_free(format->tabs);
115 heap_free(format);
116
117 return Ok;
118 }
119
GdipStringFormatGetGenericDefault(GpStringFormat ** format)120 GpStatus WINGDIPAPI GdipStringFormatGetGenericDefault(GpStringFormat **format)
121 {
122 if (!format)
123 return InvalidParameter;
124
125 *format = &generic_default_format;
126
127 return Ok;
128 }
129
GdipGetStringFormatAlign(GpStringFormat * format,StringAlignment * align)130 GpStatus WINGDIPAPI GdipGetStringFormatAlign(GpStringFormat *format,
131 StringAlignment *align)
132 {
133 if(!format || !align)
134 return InvalidParameter;
135
136 *align = format->align;
137
138 return Ok;
139 }
140
GdipGetStringFormatDigitSubstitution(GDIPCONST GpStringFormat * format,LANGID * language,StringDigitSubstitute * substitute)141 GpStatus WINGDIPAPI GdipGetStringFormatDigitSubstitution(GDIPCONST GpStringFormat *format,
142 LANGID *language, StringDigitSubstitute *substitute)
143 {
144 if(!format)
145 return InvalidParameter;
146
147 if(language) *language = format->digitlang;
148 if(substitute) *substitute = format->digitsub;
149
150 return Ok;
151 }
152
GdipGetStringFormatFlags(GDIPCONST GpStringFormat * format,INT * flags)153 GpStatus WINGDIPAPI GdipGetStringFormatFlags(GDIPCONST GpStringFormat* format,
154 INT* flags)
155 {
156 if (!(format && flags))
157 return InvalidParameter;
158
159 *flags = format->attr;
160
161 return Ok;
162 }
163
GdipGetStringFormatHotkeyPrefix(GDIPCONST GpStringFormat * format,INT * hkpx)164 GpStatus WINGDIPAPI GdipGetStringFormatHotkeyPrefix(GDIPCONST GpStringFormat
165 *format, INT *hkpx)
166 {
167 if(!format || !hkpx)
168 return InvalidParameter;
169
170 *hkpx = (INT)format->hkprefix;
171
172 return Ok;
173 }
174
GdipGetStringFormatLineAlign(GpStringFormat * format,StringAlignment * align)175 GpStatus WINGDIPAPI GdipGetStringFormatLineAlign(GpStringFormat *format,
176 StringAlignment *align)
177 {
178 if(!format || !align)
179 return InvalidParameter;
180
181 *align = format->line_align;
182
183 return Ok;
184 }
185
GdipGetStringFormatMeasurableCharacterRangeCount(GDIPCONST GpStringFormat * format,INT * count)186 GpStatus WINGDIPAPI GdipGetStringFormatMeasurableCharacterRangeCount(
187 GDIPCONST GpStringFormat *format, INT *count)
188 {
189 if (!(format && count))
190 return InvalidParameter;
191
192 TRACE("%p %p\n", format, count);
193
194 *count = format->range_count;
195
196 return Ok;
197 }
198
GdipGetStringFormatTabStopCount(GDIPCONST GpStringFormat * format,INT * count)199 GpStatus WINGDIPAPI GdipGetStringFormatTabStopCount(GDIPCONST GpStringFormat *format,
200 INT *count)
201 {
202 if(!format || !count)
203 return InvalidParameter;
204
205 *count = format->tabcount;
206
207 return Ok;
208 }
209
GdipGetStringFormatTabStops(GDIPCONST GpStringFormat * format,INT count,REAL * firsttab,REAL * tabs)210 GpStatus WINGDIPAPI GdipGetStringFormatTabStops(GDIPCONST GpStringFormat *format, INT count,
211 REAL *firsttab, REAL *tabs)
212 {
213 if(!format || !firsttab || !tabs)
214 return InvalidParameter;
215
216 /* native simply crashes on count < 0 */
217 if(count != 0)
218 memcpy(tabs, format->tabs, sizeof(REAL)*count);
219
220 *firsttab = format->firsttab;
221
222 return Ok;
223 }
224
GdipGetStringFormatTrimming(GpStringFormat * format,StringTrimming * trimming)225 GpStatus WINGDIPAPI GdipGetStringFormatTrimming(GpStringFormat *format,
226 StringTrimming *trimming)
227 {
228 if(!format || !trimming)
229 return InvalidParameter;
230
231 *trimming = format->trimming;
232
233 return Ok;
234 }
235
GdipSetStringFormatAlign(GpStringFormat * format,StringAlignment align)236 GpStatus WINGDIPAPI GdipSetStringFormatAlign(GpStringFormat *format,
237 StringAlignment align)
238 {
239 TRACE("(%p, %i)\n", format, align);
240
241 if(!format)
242 return InvalidParameter;
243
244 format->align = align;
245
246 return Ok;
247 }
248
249 /*FIXME: digit substitution actually not implemented, get/set only */
GdipSetStringFormatDigitSubstitution(GpStringFormat * format,LANGID language,StringDigitSubstitute substitute)250 GpStatus WINGDIPAPI GdipSetStringFormatDigitSubstitution(GpStringFormat *format,
251 LANGID language, StringDigitSubstitute substitute)
252 {
253 TRACE("(%p, %x, %i)\n", format, language, substitute);
254
255 if(!format)
256 return InvalidParameter;
257
258 format->digitlang = language;
259 format->digitsub = substitute;
260
261 return Ok;
262 }
263
GdipSetStringFormatHotkeyPrefix(GpStringFormat * format,INT hkpx)264 GpStatus WINGDIPAPI GdipSetStringFormatHotkeyPrefix(GpStringFormat *format,
265 INT hkpx)
266 {
267 TRACE("(%p, %i)\n", format, hkpx);
268
269 if(!format || hkpx < 0 || hkpx > 2)
270 return InvalidParameter;
271
272 format->hkprefix = (HotkeyPrefix) hkpx;
273
274 return Ok;
275 }
276
GdipSetStringFormatLineAlign(GpStringFormat * format,StringAlignment align)277 GpStatus WINGDIPAPI GdipSetStringFormatLineAlign(GpStringFormat *format,
278 StringAlignment align)
279 {
280 TRACE("(%p, %i)\n", format, align);
281
282 if(!format)
283 return InvalidParameter;
284
285 format->line_align = align;
286
287 return Ok;
288 }
289
GdipSetStringFormatMeasurableCharacterRanges(GpStringFormat * format,INT rangeCount,GDIPCONST CharacterRange * ranges)290 GpStatus WINGDIPAPI GdipSetStringFormatMeasurableCharacterRanges(
291 GpStringFormat *format, INT rangeCount, GDIPCONST CharacterRange *ranges)
292 {
293 CharacterRange *new_ranges;
294
295 if (!(format && ranges))
296 return InvalidParameter;
297
298 TRACE("%p, %d, %p\n", format, rangeCount, ranges);
299
300 new_ranges = heap_alloc_zero(rangeCount * sizeof(CharacterRange));
301 if (!new_ranges)
302 return OutOfMemory;
303
304 heap_free(format->character_ranges);
305 format->character_ranges = new_ranges;
306 memcpy(format->character_ranges, ranges, sizeof(CharacterRange) * rangeCount);
307 format->range_count = rangeCount;
308
309 return Ok;
310 }
311
GdipSetStringFormatTabStops(GpStringFormat * format,REAL firsttab,INT count,GDIPCONST REAL * tabs)312 GpStatus WINGDIPAPI GdipSetStringFormatTabStops(GpStringFormat *format, REAL firsttab,
313 INT count, GDIPCONST REAL *tabs)
314 {
315 TRACE("(%p, %0.2f, %i, %p)\n", format, firsttab, count, tabs);
316
317 if(!format || !tabs)
318 return InvalidParameter;
319
320 if(count > 0){
321 if(firsttab < 0.0) return NotImplemented;
322 /* first time allocation */
323 if(format->tabcount == 0){
324 format->tabs = heap_alloc_zero(sizeof(REAL)*count);
325 if(!format->tabs)
326 return OutOfMemory;
327 }
328 /* reallocation */
329 if((format->tabcount < count) && (format->tabcount > 0)){
330 REAL *ptr;
331 ptr = heap_realloc(format->tabs, sizeof(REAL)*count);
332 if(!ptr)
333 return OutOfMemory;
334 format->tabs = ptr;
335 }
336 format->firsttab = firsttab;
337 format->tabcount = count;
338 memcpy(format->tabs, tabs, sizeof(REAL)*count);
339 }
340
341 return Ok;
342 }
343
GdipSetStringFormatTrimming(GpStringFormat * format,StringTrimming trimming)344 GpStatus WINGDIPAPI GdipSetStringFormatTrimming(GpStringFormat *format,
345 StringTrimming trimming)
346 {
347 TRACE("(%p, %i)\n", format, trimming);
348
349 if(!format)
350 return InvalidParameter;
351
352 format->trimming = trimming;
353
354 return Ok;
355 }
356
GdipSetStringFormatFlags(GpStringFormat * format,INT flags)357 GpStatus WINGDIPAPI GdipSetStringFormatFlags(GpStringFormat *format, INT flags)
358 {
359 TRACE("(%p, %x)\n", format, flags);
360
361 if(!format)
362 return InvalidParameter;
363
364 format->attr = flags;
365
366 return Ok;
367 }
368
GdipCloneStringFormat(GDIPCONST GpStringFormat * format,GpStringFormat ** newFormat)369 GpStatus WINGDIPAPI GdipCloneStringFormat(GDIPCONST GpStringFormat *format, GpStringFormat **newFormat)
370 {
371 if(!format || !newFormat)
372 return InvalidParameter;
373
374 *newFormat = heap_alloc_zero(sizeof(GpStringFormat));
375 if(!*newFormat) return OutOfMemory;
376
377 **newFormat = *format;
378
379 if(format->tabcount > 0){
380 (*newFormat)->tabs = heap_alloc_zero(sizeof(REAL) * format->tabcount);
381 if(!(*newFormat)->tabs){
382 heap_free(*newFormat);
383 return OutOfMemory;
384 }
385 memcpy((*newFormat)->tabs, format->tabs, sizeof(REAL) * format->tabcount);
386 }
387 else
388 (*newFormat)->tabs = NULL;
389
390 if(format->range_count > 0){
391 (*newFormat)->character_ranges = heap_alloc_zero(sizeof(CharacterRange) * format->range_count);
392 if(!(*newFormat)->character_ranges){
393 heap_free((*newFormat)->tabs);
394 heap_free(*newFormat);
395 return OutOfMemory;
396 }
397 memcpy((*newFormat)->character_ranges, format->character_ranges,
398 sizeof(CharacterRange) * format->range_count);
399 }
400 else
401 (*newFormat)->character_ranges = NULL;
402
403 TRACE("%p %p\n",format,newFormat);
404
405 return Ok;
406 }
407
GdipStringFormatGetGenericTypographic(GpStringFormat ** format)408 GpStatus WINGDIPAPI GdipStringFormatGetGenericTypographic(GpStringFormat **format)
409 {
410 if(!format)
411 return InvalidParameter;
412
413 *format = &generic_typographic_format;
414
415 TRACE("%p => %p\n", format, *format);
416
417 return Ok;
418 }
419