1/* 2 * Copyright (C) 2006, 2009, 2012 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21#include "config.h" 22#include "wtf/text/StringImpl.h" 23 24#if USE(CF) 25 26#include "wtf/MainThread.h" 27#include "wtf/PassRefPtr.h" 28#include "wtf/RetainPtr.h" 29#include "wtf/Threading.h" 30#include <CoreFoundation/CoreFoundation.h> 31 32namespace WTF { 33 34namespace StringWrapperCFAllocator { 35 36static StringImpl* currentString; 37 38static const void* retain(const void* info) 39{ 40 return info; 41} 42 43NO_RETURN_DUE_TO_ASSERT 44static void release(const void*) 45{ 46 ASSERT_NOT_REACHED(); 47} 48 49static CFStringRef copyDescription(const void*) 50{ 51 return CFSTR("WTF::String-based allocator"); 52} 53 54static void* allocate(CFIndex size, CFOptionFlags, void*) 55{ 56 StringImpl* underlyingString = 0; 57 if (isMainThread()) { 58 underlyingString = currentString; 59 if (underlyingString) { 60 currentString = 0; 61 underlyingString->ref(); // Balanced by call to deref in deallocate below. 62 } 63 } 64 StringImpl** header = static_cast<StringImpl**>(fastMalloc(sizeof(StringImpl*) + size)); 65 *header = underlyingString; 66 return header + 1; 67} 68 69static void* reallocate(void* pointer, CFIndex newSize, CFOptionFlags, void*) 70{ 71 size_t newAllocationSize = sizeof(StringImpl*) + newSize; 72 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 73 ASSERT(!*header); 74 header = static_cast<StringImpl**>(fastRealloc(header, newAllocationSize)); 75 return header + 1; 76} 77 78static void deallocateOnMainThread(void* headerPointer) 79{ 80 StringImpl** header = static_cast<StringImpl**>(headerPointer); 81 StringImpl* underlyingString = *header; 82 ASSERT(underlyingString); 83 underlyingString->deref(); // Balanced by call to ref in allocate above. 84 fastFree(header); 85} 86 87static void deallocate(void* pointer, void*) 88{ 89 StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 90 StringImpl* underlyingString = *header; 91 if (!underlyingString) { 92 fastFree(header); 93 } else { 94 if (!isMainThread()) { 95 callOnMainThread(deallocateOnMainThread, header); 96 } else { 97 underlyingString->deref(); // Balanced by call to ref in allocate above. 98 fastFree(header); 99 } 100 } 101} 102 103static CFIndex preferredSize(CFIndex size, CFOptionFlags, void*) 104{ 105 // FIXME: If FastMalloc provided a "good size" callback, we'd want to use it here. 106 // Note that this optimization would help performance for strings created with the 107 // allocator that are mutable, and those typically are only created by callers who 108 // make a new string using the old string's allocator, such as some of the call 109 // sites in CFURL. 110 return size; 111} 112 113static CFAllocatorRef create() 114{ 115 CFAllocatorContext context = { 0, 0, retain, release, copyDescription, allocate, reallocate, deallocate, preferredSize }; 116 return CFAllocatorCreate(0, &context); 117} 118 119static CFAllocatorRef allocator() 120{ 121 static CFAllocatorRef allocator = create(); 122 return allocator; 123} 124 125} 126 127RetainPtr<CFStringRef> StringImpl::createCFString() 128{ 129 // Since garbage collection isn't compatible with custom allocators, we 130 // can't use the NoCopy variants of CFStringCreate*() when GC is enabled. 131 if (!m_length || !isMainThread()) { 132 if (is8Bit()) 133 return adoptCF(CFStringCreateWithBytes(0, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false)); 134 return adoptCF(CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(characters16()), m_length)); 135 } 136 CFAllocatorRef allocator = StringWrapperCFAllocator::allocator(); 137 138 // Put pointer to the StringImpl in a global so the allocator can store it with the CFString. 139 ASSERT(!StringWrapperCFAllocator::currentString); 140 StringWrapperCFAllocator::currentString = this; 141 142 CFStringRef string; 143 if (is8Bit()) 144 string = CFStringCreateWithBytesNoCopy(allocator, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false, kCFAllocatorNull); 145 else 146 string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(characters16()), m_length, kCFAllocatorNull); 147 // CoreFoundation might not have to allocate anything, we clear currentString in case we did not execute allocate(). 148 StringWrapperCFAllocator::currentString = 0; 149 150 return adoptCF(string); 151} 152 153// On StringImpl creation we could check if the allocator is the StringWrapperCFAllocator. 154// If it is, then we could find the original StringImpl and just return that. But to 155// do that we'd have to compute the offset from CFStringRef to the allocated block; 156// the CFStringRef is *not* at the start of an allocated block. Testing shows 1000x 157// more calls to createCFString than calls to the create functions with the appropriate 158// allocator, so it's probably not urgent optimize that case. 159 160} 161 162#endif // USE(CF) 163