// Copyright 2012 The Chromium Authors
// 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_type_converters.h"
#include <AppKit/AppKit.h>
#include "base/apple/bridging.h"
#include "base/apple/foundation_util.h"
#include "base/check.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/common_param_traits.h"
namespace mojo {
namespace {
NSDictionary* ToAttributesDictionary(std::u16string name, float font_size) {
DCHECK(!name.empty());
NSFont* font = [NSFont fontWithName:base::SysUTF16ToNSString(name)
size:font_size];
if (!font) {
// This can happen if:
// - The specified font is unavailable in this process.
// - The specified font is a system font unavailable through `+[NSFont
// fontWithName:size]`.
// In either case, the system font is a reasonable substitute.
font = [NSFont systemFontOfSize:font_size];
}
return @{NSFontAttributeName : font};
}
} // namespace
CFAttributedStringRef
TypeConverter<CFAttributedStringRef, ui::mojom::AttributedStringPtr>::Convert(
const ui::mojom::AttributedStringPtr& mojo_attributed_string) {
// Create the return value.
NSString* plain_text =
base::SysUTF16ToNSString(mojo_attributed_string->string);
NSMutableAttributedString* decoded_string =
[[NSMutableAttributedString alloc] initWithString:plain_text];
// Iterate over all the encoded attributes, attaching each to the string.
const std::vector<ui::mojom::FontAttributePtr>& attributes =
mojo_attributed_string->attributes;
for (const auto& attribute : attributes) {
// Protect against ranges that are outside the range of the string.
const gfx::Range& range = attribute.get()->effective_range;
if (range.GetMin() > plain_text.length ||
range.GetMax() > plain_text.length) {
continue;
}
[decoded_string
addAttributes:ToAttributesDictionary(attribute.get()->font_name,
attribute.get()->font_point_size)
range:range.ToNSRange()];
}
return static_cast<CFAttributedStringRef>(
CFAutorelease(base::apple::NSToCFOwnershipCast(decoded_string)));
}
ui::mojom::AttributedStringPtr
TypeConverter<ui::mojom::AttributedStringPtr, CFAttributedStringRef>::Convert(
const CFAttributedStringRef cf_attributed_string) {
NSAttributedString* ns_attributed_string =
base::apple::CFToNSPtrCast(cf_attributed_string);
// Create the return value.
ui::mojom::AttributedStringPtr attributed_string =
ui::mojom::AttributedString::New();
attributed_string->string =
base::SysNSStringToUTF16(ns_attributed_string.string);
// Iterate over all the attributes in the string.
NSUInteger length = ns_attributed_string.length;
for (NSUInteger i = 0; i < length;) {
NSRange effective_range;
NSDictionary* ns_attributes =
[ns_attributed_string attributesAtIndex:i
effectiveRange:&effective_range];
NSFont* font = ns_attributes[NSFontAttributeName];
std::u16string font_name;
float font_point_size;
// Only encode the attributes if the filtered set contains font information.
if (font) {
font_name = base::SysNSStringToUTF16(font.fontName);
font_point_size = font.pointSize;
if (!font_name.empty()) {
// Convert the attributes.
ui::mojom::FontAttributePtr attrs = ui::mojom::FontAttribute::New(
font_name, font_point_size, gfx::Range(effective_range));
attributed_string->attributes.push_back(std::move(attrs));
}
}
// Advance the iterator to the position outside of the effective range.
i = NSMaxRange(effective_range);
}
return attributed_string;
}
} // namespace mojo