Sync with trunk (r48545)
[reactos.git] / dll / win32 / gdiplus / stringformat.c
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 GpStatus WINGDIPAPI GdipCreateStringFormat(INT attr, LANGID lang,
36 GpStringFormat **format)
37 {
38 TRACE("(%i, %x, %p)\n", attr, lang, format);
39
40 if(!format)
41 return InvalidParameter;
42
43 *format = GdipAlloc(sizeof(GpStringFormat));
44 if(!*format) return OutOfMemory;
45
46 (*format)->attr = attr;
47 (*format)->lang = lang;
48 (*format)->digitlang = LANG_NEUTRAL;
49 (*format)->trimming = StringTrimmingCharacter;
50 (*format)->digitsub = StringDigitSubstituteUser;
51 (*format)->character_ranges = NULL;
52 (*format)->range_count = 0;
53 /* tabstops */
54 (*format)->tabcount = 0;
55 (*format)->firsttab = 0.0;
56 (*format)->tabs = NULL;
57
58 TRACE("<-- %p\n", *format);
59
60 return Ok;
61 }
62
63 GpStatus WINGDIPAPI GdipDeleteStringFormat(GpStringFormat *format)
64 {
65 if(!format)
66 return InvalidParameter;
67
68 GdipFree(format->character_ranges);
69 GdipFree(format->tabs);
70 GdipFree(format);
71
72 return Ok;
73 }
74
75 GpStatus WINGDIPAPI GdipStringFormatGetGenericDefault(GpStringFormat **format)
76 {
77 GpStatus stat;
78
79 if (!format)
80 return InvalidParameter;
81
82 stat = GdipCreateStringFormat(0, LANG_NEUTRAL, format);
83 if(stat != Ok)
84 return stat;
85
86 (*format)->align = StringAlignmentNear;
87 (*format)->vertalign = StringAlignmentNear;
88
89 return Ok;
90 }
91
92 GpStatus WINGDIPAPI GdipGetStringFormatAlign(GpStringFormat *format,
93 StringAlignment *align)
94 {
95 if(!format || !align)
96 return InvalidParameter;
97
98 *align = format->align;
99
100 return Ok;
101 }
102
103 GpStatus WINGDIPAPI GdipGetStringFormatDigitSubstitution(GDIPCONST GpStringFormat *format,
104 LANGID *language, StringDigitSubstitute *substitute)
105 {
106 if(!format)
107 return InvalidParameter;
108
109 if(language) *language = format->digitlang;
110 if(substitute) *substitute = format->digitsub;
111
112 return Ok;
113 }
114
115 GpStatus WINGDIPAPI GdipGetStringFormatFlags(GDIPCONST GpStringFormat* format,
116 INT* flags)
117 {
118 if (!(format && flags))
119 return InvalidParameter;
120
121 *flags = format->attr;
122
123 return Ok;
124 }
125
126 GpStatus WINGDIPAPI GdipGetStringFormatHotkeyPrefix(GDIPCONST GpStringFormat
127 *format, INT *hkpx)
128 {
129 if(!format || !hkpx)
130 return InvalidParameter;
131
132 *hkpx = (INT)format->hkprefix;
133
134 return Ok;
135 }
136
137 GpStatus WINGDIPAPI GdipGetStringFormatLineAlign(GpStringFormat *format,
138 StringAlignment *align)
139 {
140 if(!format || !align)
141 return InvalidParameter;
142
143 *align = format->vertalign;
144
145 return Ok;
146 }
147
148 GpStatus WINGDIPAPI GdipGetStringFormatMeasurableCharacterRangeCount(
149 GDIPCONST GpStringFormat *format, INT *count)
150 {
151 if (!(format && count))
152 return InvalidParameter;
153
154 TRACE("%p %p\n", format, count);
155
156 *count = format->range_count;
157
158 return Ok;
159 }
160
161 GpStatus WINGDIPAPI GdipGetStringFormatTabStopCount(GDIPCONST GpStringFormat *format,
162 INT *count)
163 {
164 if(!format || !count)
165 return InvalidParameter;
166
167 *count = format->tabcount;
168
169 return Ok;
170 }
171
172 GpStatus WINGDIPAPI GdipGetStringFormatTabStops(GDIPCONST GpStringFormat *format, INT count,
173 REAL *firsttab, REAL *tabs)
174 {
175 if(!format || !firsttab || !tabs)
176 return InvalidParameter;
177
178 /* native simply crashes on count < 0 */
179 if(count != 0)
180 memcpy(tabs, format->tabs, sizeof(REAL)*count);
181
182 *firsttab = format->firsttab;
183
184 return Ok;
185 }
186
187 GpStatus WINGDIPAPI GdipGetStringFormatTrimming(GpStringFormat *format,
188 StringTrimming *trimming)
189 {
190 if(!format || !trimming)
191 return InvalidParameter;
192
193 *trimming = format->trimming;
194
195 return Ok;
196 }
197
198 GpStatus WINGDIPAPI GdipSetStringFormatAlign(GpStringFormat *format,
199 StringAlignment align)
200 {
201 TRACE("(%p, %i)\n", format, align);
202
203 if(!format)
204 return InvalidParameter;
205
206 format->align = align;
207
208 return Ok;
209 }
210
211 /*FIXME: digit substitution actually not implemented, get/set only */
212 GpStatus WINGDIPAPI GdipSetStringFormatDigitSubstitution(GpStringFormat *format,
213 LANGID language, StringDigitSubstitute substitute)
214 {
215 TRACE("(%p, %x, %i)\n", format, language, substitute);
216
217 if(!format)
218 return InvalidParameter;
219
220 format->digitlang = language;
221 format->digitsub = substitute;
222
223 return Ok;
224 }
225
226 GpStatus WINGDIPAPI GdipSetStringFormatHotkeyPrefix(GpStringFormat *format,
227 INT hkpx)
228 {
229 TRACE("(%p, %i)\n", format, hkpx);
230
231 if(!format || hkpx < 0 || hkpx > 2)
232 return InvalidParameter;
233
234 format->hkprefix = (HotkeyPrefix) hkpx;
235
236 return Ok;
237 }
238
239 GpStatus WINGDIPAPI GdipSetStringFormatLineAlign(GpStringFormat *format,
240 StringAlignment align)
241 {
242 TRACE("(%p, %i)\n", format, align);
243
244 if(!format)
245 return InvalidParameter;
246
247 format->vertalign = align;
248
249 return Ok;
250 }
251
252 GpStatus WINGDIPAPI GdipSetStringFormatMeasurableCharacterRanges(
253 GpStringFormat *format, INT rangeCount, GDIPCONST CharacterRange *ranges)
254 {
255 CharacterRange *new_ranges;
256
257 if (!(format && ranges))
258 return InvalidParameter;
259
260 TRACE("%p, %d, %p\n", format, rangeCount, ranges);
261
262 new_ranges = GdipAlloc(rangeCount * sizeof(CharacterRange));
263 if (!new_ranges)
264 return OutOfMemory;
265
266 GdipFree(format->character_ranges);
267 format->character_ranges = new_ranges;
268 memcpy(format->character_ranges, ranges, sizeof(CharacterRange) * rangeCount);
269 format->range_count = rangeCount;
270
271 return Ok;
272 }
273
274 GpStatus WINGDIPAPI GdipSetStringFormatTabStops(GpStringFormat *format, REAL firsttab,
275 INT count, GDIPCONST REAL *tabs)
276 {
277 TRACE("(%p, %0.2f, %i, %p)\n", format, firsttab, count, tabs);
278
279 if(!format || !tabs)
280 return InvalidParameter;
281
282 if(count > 0){
283 if(firsttab < 0.0) return NotImplemented;
284 /* first time allocation */
285 if(format->tabcount == 0){
286 format->tabs = GdipAlloc(sizeof(REAL)*count);
287 if(!format->tabs)
288 return OutOfMemory;
289 }
290 /* reallocation */
291 if((format->tabcount < count) && (format->tabcount > 0)){
292 REAL *ptr;
293 ptr = HeapReAlloc(GetProcessHeap(), 0, format->tabs, sizeof(REAL)*count);
294 if(!ptr)
295 return OutOfMemory;
296 format->tabs = ptr;
297 }
298 format->firsttab = firsttab;
299 format->tabcount = count;
300 memcpy(format->tabs, tabs, sizeof(REAL)*count);
301 }
302
303 return Ok;
304 }
305
306 GpStatus WINGDIPAPI GdipSetStringFormatTrimming(GpStringFormat *format,
307 StringTrimming trimming)
308 {
309 TRACE("(%p, %i)\n", format, trimming);
310
311 if(!format)
312 return InvalidParameter;
313
314 format->trimming = trimming;
315
316 return Ok;
317 }
318
319 GpStatus WINGDIPAPI GdipSetStringFormatFlags(GpStringFormat *format, INT flags)
320 {
321 TRACE("(%p, %x)\n", format, flags);
322
323 if(!format)
324 return InvalidParameter;
325
326 format->attr = flags;
327
328 return Ok;
329 }
330
331 GpStatus WINGDIPAPI GdipCloneStringFormat(GDIPCONST GpStringFormat *format, GpStringFormat **newFormat)
332 {
333 if(!format || !newFormat)
334 return InvalidParameter;
335
336 *newFormat = GdipAlloc(sizeof(GpStringFormat));
337 if(!*newFormat) return OutOfMemory;
338
339 **newFormat = *format;
340
341 if(format->tabcount > 0){
342 (*newFormat)->tabs = GdipAlloc(sizeof(REAL) * format->tabcount);
343 if(!(*newFormat)->tabs){
344 GdipFree(*newFormat);
345 return OutOfMemory;
346 }
347 memcpy((*newFormat)->tabs, format->tabs, sizeof(REAL) * format->tabcount);
348 }
349 else
350 (*newFormat)->tabs = NULL;
351
352 if(format->range_count > 0){
353 (*newFormat)->character_ranges = GdipAlloc(sizeof(CharacterRange) * format->range_count);
354 if(!(*newFormat)->character_ranges){
355 GdipFree((*newFormat)->tabs);
356 GdipFree(*newFormat);
357 return OutOfMemory;
358 }
359 memcpy((*newFormat)->character_ranges, format->character_ranges,
360 sizeof(CharacterRange) * format->range_count);
361 }
362 else
363 (*newFormat)->character_ranges = NULL;
364
365 TRACE("%p %p\n",format,newFormat);
366
367 return Ok;
368 }
369
370 GpStatus WINGDIPAPI GdipStringFormatGetGenericTypographic(GpStringFormat **format)
371 {
372 GpStatus stat;
373
374 if(!format)
375 return InvalidParameter;
376
377 stat = GdipCreateStringFormat(StringFormatFlagsNoFitBlackBox |
378 StringFormatFlagsLineLimit |
379 StringFormatFlagsNoClip, LANG_NEUTRAL, format);
380 if(stat != Ok)
381 return stat;
382
383 (*format)->digitlang = LANG_NEUTRAL;
384 (*format)->digitsub = StringDigitSubstituteUser;
385 (*format)->trimming = StringTrimmingNone;
386 (*format)->hkprefix = HotkeyPrefixNone;
387 (*format)->align = StringAlignmentNear;
388 (*format)->vertalign = StringAlignmentNear;
389
390 return Ok;
391 }