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