#include "config.h"
#include <wtf/text/StringImpl.h>
#if USE(CF)
#include <CoreFoundation/CoreFoundation.h>
#include <wtf/MainThread.h>
#include <wtf/PassRefPtr.h>
#include <wtf/Threading.h>
#if PLATFORM(MAC)
#include <objc/objc-auto.h>
#endif
namespace WTF {
namespace StringWrapperCFAllocator {
static StringImpl* currentString;
static const void* retain(const void* info)
{
return info;
}
NO_RETURN_DUE_TO_ASSERT
static void release(const void*)
{
ASSERT_NOT_REACHED();
}
static CFStringRef copyDescription(const void*)
{
return CFSTR("WTF::String-based allocator");
}
static void* allocate(CFIndex size, CFOptionFlags, void*)
{
StringImpl* underlyingString = 0;
if (isMainThread()) {
underlyingString = currentString;
if (underlyingString) {
currentString = 0;
underlyingString->ref(); }
}
StringImpl** header = static_cast<StringImpl**>(fastMalloc(sizeof(StringImpl*) + size));
*header = underlyingString;
return header + 1;
}
static void* reallocate(void* pointer, CFIndex newSize, CFOptionFlags, void*)
{
size_t newAllocationSize = sizeof(StringImpl*) + newSize;
StringImpl** header = static_cast<StringImpl**>(pointer) - 1;
ASSERT(!*header);
header = static_cast<StringImpl**>(fastRealloc(header, newAllocationSize));
return header + 1;
}
static void deallocateOnMainThread(void* headerPointer)
{
StringImpl** header = static_cast<StringImpl**>(headerPointer);
StringImpl* underlyingString = *header;
ASSERT(underlyingString);
underlyingString->deref(); fastFree(header);
}
static void deallocate(void* pointer, void*)
{
StringImpl** header = static_cast<StringImpl**>(pointer) - 1;
StringImpl* underlyingString = *header;
if (!underlyingString)
fastFree(header);
else {
if (!isMainThread())
callOnMainThread(deallocateOnMainThread, header);
else {
underlyingString->deref(); fastFree(header);
}
}
}
static CFIndex preferredSize(CFIndex size, CFOptionFlags, void*)
{
return size;
}
static CFAllocatorRef create()
{
#if PLATFORM(MAC)
if (objc_collectingEnabled())
return 0;
#endif
CFAllocatorContext context = { 0, 0, retain, release, copyDescription, allocate, reallocate, deallocate, preferredSize };
return CFAllocatorCreate(0, &context);
}
static CFAllocatorRef allocator()
{
static CFAllocatorRef allocator = create();
return allocator;
}
}
CFStringRef StringImpl::createCFString()
{
CFAllocatorRef allocator = (m_length && isMainThread()) ? StringWrapperCFAllocator::allocator() : 0;
if (!allocator)
return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(characters()), m_length);
ASSERT(!StringWrapperCFAllocator::currentString);
StringWrapperCFAllocator::currentString = this;
CFStringRef string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(characters()), m_length, kCFAllocatorNull);
ASSERT(!StringWrapperCFAllocator::currentString);
StringWrapperCFAllocator::currentString = 0;
return string;
}
}
#endif // USE(CF)