1  /*
2   * Copyright (C) 2018 The Android Open Source Project
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *      http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  #ifndef DEX_LAYOUT_COMPILER_H_
18  #define DEX_LAYOUT_COMPILER_H_
19  
20  #include "dex_builder.h"
21  
22  #include <codecvt>
23  #include <locale>
24  #include <string>
25  #include <vector>
26  
27  namespace startop {
28  
29  // This visitor does the actual view compilation, using a supplied builder.
30  template <typename Builder>
31  class LayoutCompilerVisitor {
32   public:
LayoutCompilerVisitor(Builder * builder)33    explicit LayoutCompilerVisitor(Builder* builder) : builder_{builder} {}
34  
VisitStartDocument()35    void VisitStartDocument() { builder_->Start(); }
VisitEndDocument()36    void VisitEndDocument() { builder_->Finish(); }
VisitStartTag(const std::u16string & name)37    void VisitStartTag(const std::u16string& name) {
38      parent_stack_.push_back(ViewEntry{
39          std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(name), {}});
40    }
VisitEndTag()41    void VisitEndTag() {
42      auto entry = parent_stack_.back();
43      parent_stack_.pop_back();
44  
45      if (parent_stack_.empty()) {
46        GenerateCode(entry);
47      } else {
48        parent_stack_.back().children.push_back(entry);
49      }
50    }
51  
52   private:
53    struct ViewEntry {
54      std::string name;
55      std::vector<ViewEntry> children;
56    };
57  
GenerateCode(const ViewEntry & view)58    void GenerateCode(const ViewEntry& view) {
59      builder_->StartView(view.name, !view.children.empty());
60      for (const auto& child : view.children) {
61        GenerateCode(child);
62      }
63      builder_->FinishView();
64    }
65  
66    Builder* builder_;
67  
68    std::vector<ViewEntry> parent_stack_;
69  };
70  
71  class DexViewBuilder {
72   public:
73    DexViewBuilder(dex::MethodBuilder* method);
74  
75    void Start();
76    void Finish();
77    void StartView(const std::string& name, bool is_viewgroup);
78    void FinishView();
79  
80   private:
81    // Accessors for the stack of views that are under construction.
82    dex::LiveRegister AcquireRegister();
83    dex::Value GetCurrentView() const;
84    dex::Value GetCurrentLayoutParams() const;
85    dex::Value GetParentView() const;
86    void PopViewStack();
87  
88    // Methods to simplify building different code fragments.
89    void BuildGetLayoutInflater(dex::Value dest);
90    void BuildGetResources(dex::Value dest);
91    void BuildGetLayoutResource(dex::Value dest, dex::Value resources, dex::Value resid);
92    void BuildLayoutResourceToAttributeSet(dex::Value dest, dex::Value layout_resource);
93    void BuildXmlNext();
94    void BuildTryCreateView(dex::Value dest, dex::Value parent, dex::Value classname);
95  
96    dex::MethodBuilder* method_;
97  
98    // Parameters to the generated method
99    dex::Value const context_;
100    dex::Value const resid_;
101  
102    // Registers used for code generation
103    const dex::LiveRegister inflater_;
104    const dex::LiveRegister xml_;
105    const dex::LiveRegister attrs_;
106    const dex::LiveRegister classname_tmp_;
107  
108    const dex::MethodDeclData xml_next_;
109    const dex::MethodDeclData try_create_view_;
110    const dex::MethodDeclData generate_layout_params_;
111    const dex::MethodDeclData add_view_;
112  
113    // Keep track of the views currently in progress.
114    struct ViewEntry {
115      dex::LiveRegister view;
116      std::optional<dex::LiveRegister> layout_params;
117    };
118    std::vector<ViewEntry> view_stack_;
119  };
120  
121  }  // namespace startop
122  
123  #endif  // DEX_LAYOUT_COMPILER_H_
124