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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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