xref: /reactos/dll/win32/gdiplus/stringformat.c (revision 5f279f2d)
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