Home | History | Annotate | Download | only in ibus
      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