/* * * Copyright (C) 2007 Google (Evan Stade) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winnls.h" #include "objbase.h" #include "gdiplus.h" #include "gdiplus_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); const GpStringFormat default_drawstring_format = { 0, LANG_NEUTRAL, LANG_NEUTRAL, StringAlignmentNear, StringTrimmingCharacter, HotkeyPrefixNone, StringAlignmentNear, StringDigitSubstituteUser, 0, 0.0, NULL, NULL, 0, FALSE }; static GpStringFormat generic_default_format; static GpStringFormat generic_typographic_format; void init_generic_string_formats(void) { memcpy(&generic_default_format, &default_drawstring_format, sizeof(generic_default_format)); memcpy(&generic_typographic_format, &default_drawstring_format, sizeof(generic_typographic_format)); generic_typographic_format.attr = StringFormatFlagsNoFitBlackBox | StringFormatFlagsLineLimit | StringFormatFlagsNoClip; generic_typographic_format.trimming = StringTrimmingNone; generic_typographic_format.generic_typographic = TRUE; } void free_generic_string_formats(void) { heap_free(generic_default_format.character_ranges); heap_free(generic_default_format.tabs); heap_free(generic_typographic_format.character_ranges); heap_free(generic_typographic_format.tabs); } GpStatus WINGDIPAPI GdipCreateStringFormat(INT attr, LANGID lang, GpStringFormat **format) { TRACE("(%i, %x, %p)\n", attr, lang, format); if(!format) return InvalidParameter; *format = heap_alloc_zero(sizeof(GpStringFormat)); if(!*format) return OutOfMemory; (*format)->attr = attr; (*format)->lang = lang; (*format)->digitlang = LANG_NEUTRAL; (*format)->trimming = StringTrimmingCharacter; (*format)->digitsub = StringDigitSubstituteUser; (*format)->character_ranges = NULL; (*format)->range_count = 0; (*format)->generic_typographic = FALSE; /* tabstops */ (*format)->tabcount = 0; (*format)->firsttab = 0.0; (*format)->tabs = NULL; TRACE("<-- %p\n", *format); return Ok; } GpStatus WINGDIPAPI GdipDeleteStringFormat(GpStringFormat *format) { if(!format) return InvalidParameter; if (format == &generic_default_format || format == &generic_typographic_format) return Ok; heap_free(format->character_ranges); heap_free(format->tabs); heap_free(format); return Ok; } GpStatus WINGDIPAPI GdipStringFormatGetGenericDefault(GpStringFormat **format) { if (!format) return InvalidParameter; *format = &generic_default_format; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatAlign(GpStringFormat *format, StringAlignment *align) { if(!format || !align) return InvalidParameter; *align = format->align; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatDigitSubstitution(GDIPCONST GpStringFormat *format, LANGID *language, StringDigitSubstitute *substitute) { if(!format) return InvalidParameter; if(language) *language = format->digitlang; if(substitute) *substitute = format->digitsub; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatFlags(GDIPCONST GpStringFormat* format, INT* flags) { if (!(format && flags)) return InvalidParameter; *flags = format->attr; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatHotkeyPrefix(GDIPCONST GpStringFormat *format, INT *hkpx) { if(!format || !hkpx) return InvalidParameter; *hkpx = (INT)format->hkprefix; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatLineAlign(GpStringFormat *format, StringAlignment *align) { if(!format || !align) return InvalidParameter; *align = format->line_align; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatMeasurableCharacterRangeCount( GDIPCONST GpStringFormat *format, INT *count) { if (!(format && count)) return InvalidParameter; TRACE("%p %p\n", format, count); *count = format->range_count; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatTabStopCount(GDIPCONST GpStringFormat *format, INT *count) { if(!format || !count) return InvalidParameter; *count = format->tabcount; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatTabStops(GDIPCONST GpStringFormat *format, INT count, REAL *firsttab, REAL *tabs) { if(!format || !firsttab || !tabs) return InvalidParameter; /* native simply crashes on count < 0 */ if(count != 0) memcpy(tabs, format->tabs, sizeof(REAL)*count); *firsttab = format->firsttab; return Ok; } GpStatus WINGDIPAPI GdipGetStringFormatTrimming(GpStringFormat *format, StringTrimming *trimming) { if(!format || !trimming) return InvalidParameter; *trimming = format->trimming; return Ok; } GpStatus WINGDIPAPI GdipSetStringFormatAlign(GpStringFormat *format, StringAlignment align) { TRACE("(%p, %i)\n", format, align); if(!format) return InvalidParameter; format->align = align; return Ok; } /*FIXME: digit substitution actually not implemented, get/set only */ GpStatus WINGDIPAPI GdipSetStringFormatDigitSubstitution(GpStringFormat *format, LANGID language, StringDigitSubstitute substitute) { TRACE("(%p, %x, %i)\n", format, language, substitute); if(!format) return InvalidParameter; format->digitlang = language; format->digitsub = substitute; return Ok; } GpStatus WINGDIPAPI GdipSetStringFormatHotkeyPrefix(GpStringFormat *format, INT hkpx) { TRACE("(%p, %i)\n", format, hkpx); if(!format || hkpx < 0 || hkpx > 2) return InvalidParameter; format->hkprefix = (HotkeyPrefix) hkpx; return Ok; } GpStatus WINGDIPAPI GdipSetStringFormatLineAlign(GpStringFormat *format, StringAlignment align) { TRACE("(%p, %i)\n", format, align); if(!format) return InvalidParameter; format->line_align = align; return Ok; } GpStatus WINGDIPAPI GdipSetStringFormatMeasurableCharacterRanges( GpStringFormat *format, INT rangeCount, GDIPCONST CharacterRange *ranges) { CharacterRange *new_ranges; if (!(format && ranges)) return InvalidParameter; TRACE("%p, %d, %p\n", format, rangeCount, ranges); new_ranges = heap_alloc_zero(rangeCount * sizeof(CharacterRange)); if (!new_ranges) return OutOfMemory; heap_free(format->character_ranges); format->character_ranges = new_ranges; memcpy(format->character_ranges, ranges, sizeof(CharacterRange) * rangeCount); format->range_count = rangeCount; return Ok; } GpStatus WINGDIPAPI GdipSetStringFormatTabStops(GpStringFormat *format, REAL firsttab, INT count, GDIPCONST REAL *tabs) { TRACE("(%p, %0.2f, %i, %p)\n", format, firsttab, count, tabs); if(!format || !tabs) return InvalidParameter; if(count > 0){ if(firsttab < 0.0) return NotImplemented; /* first time allocation */ if(format->tabcount == 0){ format->tabs = heap_alloc_zero(sizeof(REAL)*count); if(!format->tabs) return OutOfMemory; } /* reallocation */ if((format->tabcount < count) && (format->tabcount > 0)){ REAL *ptr; ptr = heap_realloc(format->tabs, sizeof(REAL)*count); if(!ptr) return OutOfMemory; format->tabs = ptr; } format->firsttab = firsttab; format->tabcount = count; memcpy(format->tabs, tabs, sizeof(REAL)*count); } return Ok; } GpStatus WINGDIPAPI GdipSetStringFormatTrimming(GpStringFormat *format, StringTrimming trimming) { TRACE("(%p, %i)\n", format, trimming); if(!format) return InvalidParameter; format->trimming = trimming; return Ok; } GpStatus WINGDIPAPI GdipSetStringFormatFlags(GpStringFormat *format, INT flags) { TRACE("(%p, %x)\n", format, flags); if(!format) return InvalidParameter; format->attr = flags; return Ok; } GpStatus WINGDIPAPI GdipCloneStringFormat(GDIPCONST GpStringFormat *format, GpStringFormat **newFormat) { if(!format || !newFormat) return InvalidParameter; *newFormat = heap_alloc_zero(sizeof(GpStringFormat)); if(!*newFormat) return OutOfMemory; **newFormat = *format; if(format->tabcount > 0){ (*newFormat)->tabs = heap_alloc_zero(sizeof(REAL) * format->tabcount); if(!(*newFormat)->tabs){ heap_free(*newFormat); return OutOfMemory; } memcpy((*newFormat)->tabs, format->tabs, sizeof(REAL) * format->tabcount); } else (*newFormat)->tabs = NULL; if(format->range_count > 0){ (*newFormat)->character_ranges = heap_alloc_zero(sizeof(CharacterRange) * format->range_count); if(!(*newFormat)->character_ranges){ heap_free((*newFormat)->tabs); heap_free(*newFormat); return OutOfMemory; } memcpy((*newFormat)->character_ranges, format->character_ranges, sizeof(CharacterRange) * format->range_count); } else (*newFormat)->character_ranges = NULL; TRACE("%p %p\n",format,newFormat); return Ok; } GpStatus WINGDIPAPI GdipStringFormatGetGenericTypographic(GpStringFormat **format) { if(!format) return InvalidParameter; *format = &generic_typographic_format; TRACE("%p => %p\n", format, *format); return Ok; }