Chromium Code Reviews| Index: device/hid/hid_report_descriptor.cc |
| diff --git a/device/hid/hid_report_descriptor.cc b/device/hid/hid_report_descriptor.cc |
| index f2cb0f4901f10419b16079c372e2391d7d4bd40b..00e16cf5aeed29e4cee030ffcd477020addbb03f 100644 |
| --- a/device/hid/hid_report_descriptor.cc |
| +++ b/device/hid/hid_report_descriptor.cc |
| @@ -8,6 +8,12 @@ |
| namespace device { |
| +namespace { |
| + |
| +const int kOneByte = 8; |
|
Ken Rockot(use gerrit already)
2014/06/06 20:04:43
How about "kBitsPerByte"
jracle (use Gerrit)
2014/06/07 12:56:21
+2!
On 2014/06/06 20:04:43, Ken Rockot wrote:
|
| + |
| +} // namespace |
| + |
| HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) { |
| size_t header_index = 0; |
| HidReportDescriptorItem* item = NULL; |
| @@ -21,41 +27,147 @@ HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) { |
| HidReportDescriptor::~HidReportDescriptor() {} |
| void HidReportDescriptor::GetTopLevelCollections( |
| - std::vector<HidUsageAndPage>* topLevelCollections) { |
| - DCHECK(topLevelCollections); |
| - STLClearObject(topLevelCollections); |
| + std::vector<HidCollectionInfo>* top_level_collections, |
| + 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); |
| + |
| + *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()) { |
|
Ken Rockot(use gerrit already)
2014/06/06 20:04:43
In general this is awesome. I wish it were a littl
jracle (use Gerrit)
2014/06/07 12:56:21
Thanks, I'm also a bit uncomfortable with it, but
|
| + // 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()); |
| + |
| + // We need to increase report sizes by report ID field length. |
| + if (current_input_report_size > 0) |
| + current_input_report_size += kOneByte; |
| + if (current_output_report_size > 0) |
| + current_output_report_size += kOneByte; |
| + if (current_feature_report_size > 0) |
| + current_feature_report_size += kOneByte; |
| + |
| + // 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); |
| + |
| + // Set report sizes to be 1-byte long (report ID field). |
| + 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; |
| } |
| } |
| + |
| + if (top_level_collections->size() > 0 && |
| + top_level_collections->back().report_ids.size() > 0) { |
| + // We need to increase report sizes by report ID field length. |
| + if (current_input_report_size > 0) |
| + current_input_report_size += kOneByte; |
| + if (current_output_report_size > 0) |
| + current_output_report_size += kOneByte; |
| + if (current_feature_report_size > 0) |
| + current_feature_report_size += kOneByte; |
| + } |
| + |
| + // 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 /= kOneByte; |
| + *max_output_report_size /= kOneByte; |
| + *max_feature_report_size /= kOneByte; |
| } |
| } // namespace device |