1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chromeos/dbus/ibus/ibus_text.h" 6 7 #include "base/logging.h" 8 #include "base/values.h" 9 #include "chromeos/dbus/ibus/ibus_object.h" 10 #include "dbus/message.h" 11 12 namespace chromeos { 13 14 namespace { 15 const uint32 kAttributeUnderline = 1; // Indicates underline attribute. 16 const uint32 kAttributeSelection = 2; // Indicates background attribute. 17 const char kAnnotationKey[] = "annotation"; 18 const char kDescriptionTitleKey[] = "description_title"; 19 const char kDescriptionBodyKey[] = "description_body"; 20 21 struct IBusAttribute { 22 IBusAttribute() : type(0), value(0), start_index(0), end_index(0) {} 23 uint32 type; 24 uint32 value; 25 uint32 start_index; 26 uint32 end_index; 27 }; 28 29 // Pops a IBusAttribute from |reader|. 30 // Returns false if an error occurs. 31 bool PopIBusAttribute(dbus::MessageReader* reader, IBusAttribute* attribute) { 32 IBusObjectReader ibus_object_reader("IBusAttribute", reader); 33 if (!ibus_object_reader.Init()) 34 return false; 35 36 if (!ibus_object_reader.PopUint32(&attribute->type) || 37 !ibus_object_reader.PopUint32(&attribute->value) || 38 !ibus_object_reader.PopUint32(&attribute->start_index) || 39 !ibus_object_reader.PopUint32(&attribute->end_index)) { 40 LOG(ERROR) << "Invalid variant structure[IBusAttribute]: " 41 << "IBusAttribute should contain 4 unsigned integers."; 42 return false; 43 } 44 return true; 45 } 46 47 // Appends a IBusAttribute into |writer|. 48 void AppendIBusAttribute(dbus::MessageWriter* writer, 49 const IBusAttribute& attribute) { 50 IBusObjectWriter ibus_attribute_writer("IBusAttribute", "uuuu", writer); 51 ibus_attribute_writer.CloseHeader(); 52 ibus_attribute_writer.AppendUint32(attribute.type); 53 ibus_attribute_writer.AppendUint32(attribute.value); 54 ibus_attribute_writer.AppendUint32(attribute.start_index); 55 ibus_attribute_writer.AppendUint32(attribute.end_index); 56 ibus_attribute_writer.CloseAll(); 57 } 58 59 } // namespace 60 61 void AppendIBusText(const IBusText& ibus_text, dbus::MessageWriter* writer) { 62 IBusObjectWriter ibus_text_writer("IBusText", "sv", writer); 63 64 if (!ibus_text.annotation().empty()) { 65 scoped_ptr<base::Value> annotation( 66 base::Value::CreateStringValue(ibus_text.annotation())); 67 ibus_text_writer.AddAttachment(kAnnotationKey, *annotation.get()); 68 } 69 if (!ibus_text.description_title().empty()) { 70 scoped_ptr<base::Value> description_title( 71 base::Value::CreateStringValue(ibus_text.description_title())); 72 ibus_text_writer.AddAttachment(kDescriptionTitleKey, 73 *description_title.get()); 74 } 75 if (!ibus_text.description_body().empty()) { 76 scoped_ptr<base::Value> description_body( 77 base::Value::CreateStringValue(ibus_text.description_body())); 78 ibus_text_writer.AddAttachment(kDescriptionBodyKey, 79 *description_body.get()); 80 } 81 ibus_text_writer.CloseHeader(); 82 83 ibus_text_writer.AppendString(ibus_text.text()); 84 85 // Start appending IBusAttrList into IBusText 86 IBusObjectWriter ibus_attr_list_writer("IBusAttrList", "av", NULL); 87 ibus_text_writer.AppendIBusObject(&ibus_attr_list_writer); 88 ibus_attr_list_writer.CloseHeader(); 89 dbus::MessageWriter attribute_array_writer(NULL); 90 ibus_attr_list_writer.OpenArray("v", &attribute_array_writer); 91 92 const std::vector<IBusText::UnderlineAttribute>& underline_attributes = 93 ibus_text.underline_attributes(); 94 for (size_t i = 0; i < underline_attributes.size(); ++i) { 95 IBusAttribute attribute; 96 attribute.type = kAttributeUnderline; 97 attribute.value = static_cast<uint32>(underline_attributes[i].type); 98 attribute.start_index = underline_attributes[i].start_index; 99 attribute.end_index = underline_attributes[i].end_index; 100 AppendIBusAttribute(&attribute_array_writer, attribute); 101 } 102 103 const std::vector<IBusText::SelectionAttribute>& selection_attributes = 104 ibus_text.selection_attributes(); 105 for (size_t i = 0; i < selection_attributes.size(); ++i) { 106 IBusAttribute attribute; 107 attribute.type = kAttributeSelection; 108 attribute.value = 0; 109 attribute.start_index = selection_attributes[i].start_index; 110 attribute.end_index = selection_attributes[i].end_index; 111 AppendIBusAttribute(&attribute_array_writer, attribute); 112 } 113 114 // Close all writers. 115 ibus_attr_list_writer.CloseContainer(&attribute_array_writer); 116 ibus_attr_list_writer.CloseAll(); 117 ibus_text_writer.CloseAll(); 118 } 119 120 void CHROMEOS_EXPORT AppendStringAsIBusText(const std::string& text, 121 dbus::MessageWriter* writer) { 122 IBusText ibus_text; 123 ibus_text.set_text(text); 124 AppendIBusText(ibus_text, writer); 125 } 126 127 bool PopIBusText(dbus::MessageReader* reader, IBusText* ibus_text) { 128 IBusObjectReader ibus_text_reader("IBusText", reader); 129 130 if (!ibus_text_reader.Init()) 131 return false; 132 133 const base::Value* annotation_value = 134 ibus_text_reader.GetAttachment(kAnnotationKey); 135 if (annotation_value) { 136 std::string annotation; 137 if (annotation_value->GetAsString(&annotation)) 138 ibus_text->set_annotation(annotation); 139 } 140 141 const base::Value* description_title_value = 142 ibus_text_reader.GetAttachment(kDescriptionTitleKey); 143 if (description_title_value) { 144 std::string description_title; 145 if (description_title_value->GetAsString(&description_title)) 146 ibus_text->set_description_title(description_title); 147 } 148 149 const base::Value* description_body_value = 150 ibus_text_reader.GetAttachment(kDescriptionBodyKey); 151 if (description_body_value) { 152 std::string description_body; 153 if (description_body_value->GetAsString(&description_body)) 154 ibus_text->set_description_body(description_body); 155 } 156 157 std::string text; 158 if (!ibus_text_reader.PopString(&text)) { 159 LOG(ERROR) << "Invalid variant structure[IBusText]: " 160 << "1st argument should be string."; 161 return false; 162 } 163 164 ibus_text->set_text(text); 165 166 // Start reading IBusAttrList object 167 IBusObjectReader ibus_attr_list_reader("IBusAttrList", NULL); 168 if (!ibus_text_reader.PopIBusObject(&ibus_attr_list_reader)) { 169 LOG(ERROR) << "Invalid variant structure[IBusText]: " 170 << "2nd argument should be IBusAttrList."; 171 return false; 172 } 173 174 dbus::MessageReader attribute_array_reader(NULL); 175 if (!ibus_attr_list_reader.PopArray(&attribute_array_reader)) { 176 LOG(ERROR) << "Invalid variant structure[IBusAttrList]: " 177 << "1st argument should be array of IBusAttribute."; 178 return false; 179 } 180 181 std::vector<IBusText::UnderlineAttribute>* underline_attributes = 182 ibus_text->mutable_underline_attributes(); 183 184 std::vector<IBusText::SelectionAttribute>* selection_attributes = 185 ibus_text->mutable_selection_attributes(); 186 187 while (attribute_array_reader.HasMoreData()) { 188 IBusAttribute attribute; 189 if (!PopIBusAttribute(&attribute_array_reader, &attribute)) 190 return false; 191 192 if (attribute.type == kAttributeUnderline) { 193 IBusText::UnderlineAttribute underline_attribute; 194 underline_attribute.type = 195 static_cast<IBusText::IBusTextUnderlineType>(attribute.value); 196 underline_attribute.start_index = attribute.start_index; 197 underline_attribute.end_index = attribute.end_index; 198 underline_attributes->push_back(underline_attribute); 199 } else if (attribute.type == kAttributeSelection) { 200 IBusText::SelectionAttribute selection_attribute; 201 selection_attribute.start_index = attribute.start_index; 202 selection_attribute.end_index = attribute.end_index; 203 selection_attributes->push_back(selection_attribute); 204 } else { 205 DVLOG(1) << "Chrome does not support background attribute."; 206 } 207 } 208 209 return true; 210 } 211 212 bool CHROMEOS_EXPORT PopStringFromIBusText(dbus::MessageReader* reader, 213 std::string* text) { 214 IBusText ibus_text; 215 if (!PopIBusText(reader, &ibus_text)) 216 return false; 217 *text = ibus_text.text(); 218 return true; 219 } 220 221 /////////////////////////////////////////////////////////////////////////////// 222 // IBusText 223 IBusText::IBusText() 224 : text_("") { 225 } 226 227 IBusText::~IBusText() { 228 } 229 230 void IBusText::CopyFrom(const IBusText& obj) { 231 text_ = obj.text(); 232 annotation_ = obj.annotation(); 233 description_title_ = obj.description_title(); 234 description_body_ = obj.description_body(); 235 underline_attributes_ = obj.underline_attributes(); 236 selection_attributes_ = obj.selection_attributes(); 237 } 238 239 } // namespace chromeos 240