15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2006, 2009, 2012 Apple Inc. All rights reserved. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Library General Public 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2 of the License, or (at your option) any later version. 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful, 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Library General Public License for more details. 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Library General Public License 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * along with this library; see the file COPYING.LIB. If not, write to 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Boston, MA 02110-1301, USA. 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/text/StringImpl.h" 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if USE(CF) 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/MainThread.h" 277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/PassRefPtr.h" 287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/RetainPtr.h" 297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/Threading.h" 301e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include <CoreFoundation/CoreFoundation.h> 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WTF { 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace StringWrapperCFAllocator { 355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static StringImpl* currentString; 375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 381e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static const void* retain(const void* info) 391e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) return info; 411e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 431e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)NO_RETURN_DUE_TO_ASSERT 441e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static void release(const void*) 451e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 461e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) ASSERT_NOT_REACHED(); 471e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 491e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static CFStringRef copyDescription(const void*) 501e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 511e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) return CFSTR("WTF::String-based allocator"); 521e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 541e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static void* allocate(CFIndex size, CFOptionFlags, void*) 551e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 561e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) StringImpl* underlyingString = 0; 571e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) if (isMainThread()) { 581e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) underlyingString = currentString; 591e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) if (underlyingString) { 601e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) currentString = 0; 611e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) underlyingString->ref(); // Balanced by call to deref in deallocate below. 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 641e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) StringImpl** header = static_cast<StringImpl**>(fastMalloc(sizeof(StringImpl*) + size)); 651e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) *header = underlyingString; 661e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) return header + 1; 671e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 691e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static void* reallocate(void* pointer, CFIndex newSize, CFOptionFlags, void*) 701e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 711e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) size_t newAllocationSize = sizeof(StringImpl*) + newSize; 721e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 731e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) ASSERT(!*header); 741e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) header = static_cast<StringImpl**>(fastRealloc(header, newAllocationSize)); 751e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) return header + 1; 761e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 781e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static void deallocateOnMainThread(void* headerPointer) 791e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 801e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) StringImpl** header = static_cast<StringImpl**>(headerPointer); 811e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) StringImpl* underlyingString = *header; 821e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) ASSERT(underlyingString); 831e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) underlyingString->deref(); // Balanced by call to ref in allocate above. 841e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) fastFree(header); 851e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 871e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static void deallocate(void* pointer, void*) 881e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 891e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) StringImpl** header = static_cast<StringImpl**>(pointer) - 1; 901e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) StringImpl* underlyingString = *header; 911e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) if (!underlyingString) { 921e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) fastFree(header); 931e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) } else { 941e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) if (!isMainThread()) { 951e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) callOnMainThread(deallocateOnMainThread, header); 961e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) } else { 971e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) underlyingString->deref(); // Balanced by call to ref in allocate above. 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fastFree(header); 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1011e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1031e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static CFIndex preferredSize(CFIndex size, CFOptionFlags, void*) 1041e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 1051e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) // FIXME: If FastMalloc provided a "good size" callback, we'd want to use it here. 1061e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) // Note that this optimization would help performance for strings created with the 1071e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) // allocator that are mutable, and those typically are only created by callers who 1081e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) // make a new string using the old string's allocator, such as some of the call 1091e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) // sites in CFURL. 1101e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) return size; 1111e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1131e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static CFAllocatorRef create() 1141e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 1151e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) CFAllocatorContext context = { 0, 0, retain, release, copyDescription, allocate, reallocate, deallocate, preferredSize }; 1161e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) return CFAllocatorCreate(0, &context); 1171e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1191e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)static CFAllocatorRef allocator() 1201e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles){ 1211e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) static CFAllocatorRef allocator = create(); 1221e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) return allocator; 1231e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)} 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RetainPtr<CFStringRef> StringImpl::createCFString() 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 129926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // Since garbage collection isn't compatible with custom allocators, we 130926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // can't use the NoCopy variants of CFStringCreate*() when GC is enabled. 13153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if (!m_length || !isMainThread()) { 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (is8Bit()) 133926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return adoptCF(CFStringCreateWithBytes(0, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false)); 134926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return adoptCF(CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(characters16()), m_length)); 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) CFAllocatorRef allocator = StringWrapperCFAllocator::allocator(); 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Put pointer to the StringImpl in a global so the allocator can store it with the CFString. 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(!StringWrapperCFAllocator::currentString); 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringWrapperCFAllocator::currentString = this; 1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) CFStringRef string; 1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (is8Bit()) 1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) string = CFStringCreateWithBytesNoCopy(allocator, reinterpret_cast<const UInt8*>(characters8()), m_length, kCFStringEncodingISOLatin1, false, kCFAllocatorNull); 1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(characters16()), m_length, kCFAllocatorNull); 1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // CoreFoundation might not have to allocate anything, we clear currentString in case we did not execute allocate(). 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringWrapperCFAllocator::currentString = 0; 1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return adoptCF(string); 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// On StringImpl creation we could check if the allocator is the StringWrapperCFAllocator. 1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// If it is, then we could find the original StringImpl and just return that. But to 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// do that we'd have to compute the offset from CFStringRef to the allocated block; 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// the CFStringRef is *not* at the start of an allocated block. Testing shows 1000x 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// more calls to createCFString than calls to the create functions with the appropriate 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// allocator, so it's probably not urgent optimize that case. 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif // USE(CF) 163