gdi32/tests: Add tests for GetGlyphOutlineA.
[wine] / dlls / 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 }