blob: 85ceeb3655e6412edb76e330a7a294149203c1a1 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/common/mac/attributed_string_coder.h"
#include <AppKit/AppKit.h>
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "content/common/render_process_messages.h"
#include "content/public/common/common_param_traits.h"
#include "ipc/ipc_message_utils.h"
namespace mac {
// static
const AttributedStringCoder::EncodedString* AttributedStringCoder::Encode(
NSAttributedString* str) {
// Create the return value.
EncodedString* encoded_string =
new EncodedString(base::SysNSStringToUTF16([str string]));
// Iterate over all the attributes in the string.
NSUInteger length = [str length];
for (NSUInteger i = 0; i < length; ) {
NSRange effective_range;
NSDictionary* ns_attributes = [str attributesAtIndex:i
effectiveRange:&effective_range];
// Convert the attributes to IPC-friendly types.
FontAttribute attrs(ns_attributes, gfx::Range(effective_range));
// Only encode the attributes if the filtered set contains font information.
if (attrs.ShouldEncode()) {
encoded_string->attributes()->push_back(attrs);
}
// Advance the iterator to the position outside of the effective range.
i = NSMaxRange(effective_range);
}
return encoded_string;
}
// static
NSAttributedString* AttributedStringCoder::Decode(
const AttributedStringCoder::EncodedString* str) {
// Create the return value.
NSString* plain_text = base::SysUTF16ToNSString(str->string());
base::scoped_nsobject<NSMutableAttributedString> decoded_string(
[[NSMutableAttributedString alloc] initWithString:plain_text]);
// Iterate over all the encoded attributes, attaching each to the string.
const std::vector<FontAttribute> attributes = str->attributes();
for (std::vector<FontAttribute>::const_iterator it = attributes.begin();
it != attributes.end(); ++it) {
// Protect against ranges that are outside the range of the string.
const gfx::Range& range = it->effective_range();
if (range.GetMin() > [plain_text length] ||
range.GetMax() > [plain_text length]) {
continue;
}
[decoded_string addAttributes:it->ToAttributesDictionary()
range:range.ToNSRange()];
}
return [decoded_string.release() autorelease];
}
// Data Types //////////////////////////////////////////////////////////////////
AttributedStringCoder::EncodedString::EncodedString(base::string16 string)
: string_(string) {
}
AttributedStringCoder::EncodedString::EncodedString()
: string_() {
}
AttributedStringCoder::EncodedString::~EncodedString() {
}
AttributedStringCoder::FontAttribute::FontAttribute(NSDictionary* dict,
gfx::Range effective_range)
: font_descriptor_(),
effective_range_(effective_range) {
NSFont* font = [dict objectForKey:NSFontAttributeName];
if (font) {
font_descriptor_ = FontDescriptor(font);
}
}
AttributedStringCoder::FontAttribute::FontAttribute(FontDescriptor font,
gfx::Range range)
: font_descriptor_(font),
effective_range_(range) {
}
AttributedStringCoder::FontAttribute::FontAttribute()
: font_descriptor_(),
effective_range_() {
}
AttributedStringCoder::FontAttribute::~FontAttribute() {
}
NSDictionary*
AttributedStringCoder::FontAttribute::ToAttributesDictionary() const {
DCHECK(ShouldEncode());
NSFont* font = font_descriptor_.ToNSFont();
if (!font)
return [NSDictionary dictionary];
return [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
}
bool AttributedStringCoder::FontAttribute::ShouldEncode() const {
return !font_descriptor_.font_name.empty();
}
} // namespace mac
// IPC ParamTraits specialization //////////////////////////////////////////////
namespace IPC {
using mac::AttributedStringCoder;
void ParamTraits<AttributedStringCoder::EncodedString>::Write(
Message* m, const param_type& p) {
WriteParam(m, p.string());
WriteParam(m, p.attributes());
}
bool ParamTraits<AttributedStringCoder::EncodedString>::Read(
const Message* m,
base::PickleIterator* iter,
param_type* p) {
bool success = true;
base::string16 result;
success &= ReadParam(m, iter, &result);
*p = AttributedStringCoder::EncodedString(result);
success &= ReadParam(m, iter, p->attributes());
return success;
}
void ParamTraits<AttributedStringCoder::EncodedString>::Log(
const param_type& p, std::string* l) {
l->append(base::UTF16ToUTF8(p.string()));
}
void ParamTraits<AttributedStringCoder::FontAttribute>::Write(
Message* m, const param_type& p) {
WriteParam(m, p.font_descriptor());
WriteParam(m, p.effective_range());
}
bool ParamTraits<AttributedStringCoder::FontAttribute>::Read(
const Message* m,
base::PickleIterator* iter,
param_type* p) {
bool success = true;
FontDescriptor font;
success &= ReadParam(m, iter, &font);
gfx::Range range;
success &= ReadParam(m, iter, &range);
if (success) {
*p = AttributedStringCoder::FontAttribute(font, range);
}
return success;
}
void ParamTraits<AttributedStringCoder::FontAttribute>::Log(
const param_type& p, std::string* l) {
}
} // namespace IPC