| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef DEX_LAYOUT_COMPILER_H_ |
| #define DEX_LAYOUT_COMPILER_H_ |
| |
| #include "dex_builder.h" |
| |
| #include <codecvt> |
| #include <locale> |
| #include <string> |
| #include <vector> |
| |
| namespace startop { |
| |
| // This visitor does the actual view compilation, using a supplied builder. |
| template <typename Builder> |
| class LayoutCompilerVisitor { |
| public: |
| explicit LayoutCompilerVisitor(Builder* builder) : builder_{builder} {} |
| |
| void VisitStartDocument() { builder_->Start(); } |
| void VisitEndDocument() { builder_->Finish(); } |
| void VisitStartTag(const std::u16string& name) { |
| parent_stack_.push_back(ViewEntry{ |
| std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(name), {}}); |
| } |
| void VisitEndTag() { |
| auto entry = parent_stack_.back(); |
| parent_stack_.pop_back(); |
| |
| if (parent_stack_.empty()) { |
| GenerateCode(entry); |
| } else { |
| parent_stack_.back().children.push_back(entry); |
| } |
| } |
| |
| private: |
| struct ViewEntry { |
| std::string name; |
| std::vector<ViewEntry> children; |
| }; |
| |
| void GenerateCode(const ViewEntry& view) { |
| builder_->StartView(view.name, !view.children.empty()); |
| for (const auto& child : view.children) { |
| GenerateCode(child); |
| } |
| builder_->FinishView(); |
| } |
| |
| Builder* builder_; |
| |
| std::vector<ViewEntry> parent_stack_; |
| }; |
| |
| class DexViewBuilder { |
| public: |
| DexViewBuilder(dex::MethodBuilder* method); |
| |
| void Start(); |
| void Finish(); |
| void StartView(const std::string& name, bool is_viewgroup); |
| void FinishView(); |
| |
| private: |
| // Accessors for the stack of views that are under construction. |
| dex::Value AcquireRegister(); |
| void ReleaseRegister(); |
| dex::Value GetCurrentView() const; |
| dex::Value GetCurrentLayoutParams() const; |
| dex::Value GetParentView() const; |
| void PopViewStack(); |
| |
| dex::MethodBuilder* method_; |
| |
| // Registers used for code generation |
| dex::Value const context_; |
| dex::Value const resid_; |
| const dex::Value inflater_; |
| const dex::Value xml_; |
| const dex::Value attrs_; |
| const dex::Value classname_tmp_; |
| |
| const dex::MethodDeclData xml_next_; |
| const dex::MethodDeclData try_create_view_; |
| const dex::MethodDeclData generate_layout_params_; |
| const dex::MethodDeclData add_view_; |
| |
| // used for keeping track of which registers are in use |
| size_t top_register_{0}; |
| std::vector<dex::Value> register_stack_; |
| |
| // Keep track of the views currently in progress. |
| struct ViewEntry { |
| dex::Value view; |
| std::optional<dex::Value> layout_params; |
| }; |
| std::vector<ViewEntry> view_stack_; |
| }; |
| |
| } // namespace startop |
| |
| #endif // DEX_LAYOUT_COMPILER_H_ |