Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / device / hid / hid_report_descriptor.cc
index f2cb0f4..c461004 100644 (file)
@@ -8,6 +8,12 @@
 
 namespace device {
 
+namespace {
+
+const int kBitsPerByte = 8;
+
+}  // namespace
+
 HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
   size_t header_index = 0;
   HidReportDescriptorItem* item = NULL;
@@ -20,42 +26,132 @@ HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
 
 HidReportDescriptor::~HidReportDescriptor() {}
 
-void HidReportDescriptor::GetTopLevelCollections(
-    std::vector<HidUsageAndPage>* topLevelCollections) {
-  DCHECK(topLevelCollections);
-  STLClearObject(topLevelCollections);
+void HidReportDescriptor::GetDetails(
+    std::vector<HidCollectionInfo>* top_level_collections,
+    bool* has_report_id,
+    int* max_input_report_size,
+    int* max_output_report_size,
+    int* max_feature_report_size) {
+  DCHECK(top_level_collections);
+  DCHECK(max_input_report_size);
+  DCHECK(max_output_report_size);
+  DCHECK(max_feature_report_size);
+  STLClearObject(top_level_collections);
+
+  *has_report_id = false;
+  *max_input_report_size = 0;
+  *max_output_report_size = 0;
+  *max_feature_report_size = 0;
+
+  // Global tags data:
+  HidUsageAndPage::Page current_usage_page = HidUsageAndPage::kPageUndefined;
+  int current_report_count = 0;
+  int cached_report_count = 0;
+  int current_report_size = 0;
+  int cached_report_size = 0;
+  int current_input_report_size = 0;
+  int current_output_report_size = 0;
+  int current_feature_report_size = 0;
+
+  // Local tags data:
+  uint16_t current_usage = 0;
 
   for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator
            items_iter = items().begin();
        items_iter != items().end();
        ++items_iter) {
-    linked_ptr<HidReportDescriptorItem> item = *items_iter;
-
-    bool isTopLevelCollection =
-        item->tag() == HidReportDescriptorItem::kTagCollection &&
-        item->parent() == NULL;
-
-    if (isTopLevelCollection) {
-      uint16_t collection_usage = 0;
-      HidUsageAndPage::Page collection_usage_page =
-          HidUsageAndPage::kPageUndefined;
-
-      HidReportDescriptorItem* usage = item->previous();
-      if (usage && usage->tag() == HidReportDescriptorItem::kTagUsage) {
-        collection_usage = usage->GetShortData();
-      }
-
-      HidReportDescriptorItem* usage_page = usage->previous();
-      if (usage_page &&
-          usage_page->tag() == HidReportDescriptorItem::kTagUsagePage) {
-        collection_usage_page =
-            (HidUsageAndPage::Page)usage_page->GetShortData();
-      }
-
-      topLevelCollections->push_back(
-          HidUsageAndPage(collection_usage, collection_usage_page));
+    linked_ptr<HidReportDescriptorItem> current_item = *items_iter;
+
+    switch (current_item->tag()) {
+      // Main tags:
+      case HidReportDescriptorItem::kTagCollection:
+        if (!current_item->parent()) {
+          // This is a top-level collection.
+          HidCollectionInfo collection;
+          collection.usage = HidUsageAndPage(current_usage, current_usage_page);
+          top_level_collections->push_back(collection);
+        }
+        break;
+      case HidReportDescriptorItem::kTagInput:
+        current_input_report_size += current_report_count * current_report_size;
+        break;
+      case HidReportDescriptorItem::kTagOutput:
+        current_output_report_size +=
+            current_report_count * current_report_size;
+        break;
+      case HidReportDescriptorItem::kTagFeature:
+        current_feature_report_size +=
+            current_report_count * current_report_size;
+        break;
+
+      // Global tags:
+      case HidReportDescriptorItem::kTagUsagePage:
+        current_usage_page =
+            (HidUsageAndPage::Page)current_item->GetShortData();
+        break;
+      case HidReportDescriptorItem::kTagReportId:
+        if (top_level_collections->size() > 0) {
+          // Store report ID.
+          top_level_collections->back().report_ids.insert(
+              current_item->GetShortData());
+          *has_report_id = true;
+
+          // Update max report sizes.
+          *max_input_report_size =
+              std::max(*max_input_report_size, current_input_report_size);
+          *max_output_report_size =
+              std::max(*max_output_report_size, current_output_report_size);
+          *max_feature_report_size =
+              std::max(*max_feature_report_size, current_feature_report_size);
+
+          // Reset the report sizes for the next report ID.
+          current_input_report_size = 0;
+          current_output_report_size = 0;
+          current_feature_report_size = 0;
+        }
+        break;
+      case HidReportDescriptorItem::kTagReportCount:
+        current_report_count = current_item->GetShortData();
+        break;
+      case HidReportDescriptorItem::kTagReportSize:
+        current_report_size = current_item->GetShortData();
+        break;
+      case HidReportDescriptorItem::kTagPush:
+        // Cache report count and size.
+        cached_report_count = current_report_count;
+        cached_report_size = current_report_size;
+        break;
+      case HidReportDescriptorItem::kTagPop:
+        // Restore cache.
+        current_report_count = cached_report_count;
+        current_report_size = cached_report_size;
+        // Reset cache.
+        cached_report_count = 0;
+        cached_report_size = 0;
+        break;
+
+      // Local tags:
+      case HidReportDescriptorItem::kTagUsage:
+        current_usage = current_item->GetShortData();
+        break;
+
+      default:
+        break;
     }
   }
+
+  // Update max report sizes
+  *max_input_report_size =
+      std::max(*max_input_report_size, current_input_report_size);
+  *max_output_report_size =
+      std::max(*max_output_report_size, current_output_report_size);
+  *max_feature_report_size =
+      std::max(*max_feature_report_size, current_feature_report_size);
+
+  // Convert bits into bytes
+  *max_input_report_size /= kBitsPerByte;
+  *max_output_report_size /= kBitsPerByte;
+  *max_feature_report_size /= kBitsPerByte;
 }
 
 }  // namespace device