Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 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 | |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 17 | #include "androidfw/AttributeResolution.h" |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 18 | |
| 19 | #include <cstdint> |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 20 | |
Mark Salyzyn | 6f773a0 | 2016-09-28 16:15:30 -0700 | [diff] [blame] | 21 | #include <log/log.h> |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 22 | |
| 23 | #include "androidfw/AttributeFinder.h" |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 24 | #include "androidfw/ResourceTypes.h" |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 25 | |
| 26 | constexpr bool kDebugStyles = false; |
| 27 | |
| 28 | namespace android { |
| 29 | |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 30 | class XmlAttributeFinder |
| 31 | : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 32 | public: |
| 33 | explicit XmlAttributeFinder(const ResXMLParser* parser) |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 34 | : BackTrackingAttributeFinder( |
| 35 | 0, parser != nullptr ? parser->getAttributeCount() : 0), |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 36 | parser_(parser) {} |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 37 | |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 38 | inline uint32_t GetAttribute(size_t index) const { |
| 39 | return parser_->getAttributeNameResID(index); |
| 40 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 41 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 42 | private: |
| 43 | const ResXMLParser* parser_; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 44 | }; |
| 45 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 46 | class BagAttributeFinder |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 47 | : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 48 | public: |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 49 | BagAttributeFinder(const ResTable::bag_entry* start, |
| 50 | const ResTable::bag_entry* end) |
| 51 | : BackTrackingAttributeFinder(start, end) {} |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 52 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 53 | inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const { |
| 54 | return entry->map.name.ident; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 55 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 56 | }; |
| 57 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 58 | bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, |
| 59 | uint32_t def_style_res, uint32_t* src_values, |
| 60 | size_t src_values_length, uint32_t* attrs, |
| 61 | size_t attrs_length, uint32_t* out_values, |
| 62 | uint32_t* out_indices) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 63 | if (kDebugStyles) { |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 64 | ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme, |
| 65 | def_style_attr, def_style_res); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 66 | } |
| 67 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 68 | const ResTable& res = theme->getResTable(); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 69 | ResTable_config config; |
| 70 | Res_value value; |
| 71 | |
| 72 | int indices_idx = 0; |
| 73 | |
| 74 | // Load default style from attribute, if specified... |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 75 | uint32_t def_style_bag_type_set_flags = 0; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 76 | if (def_style_attr != 0) { |
| 77 | Res_value value; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 78 | if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 79 | if (value.dataType == Res_value::TYPE_REFERENCE) { |
| 80 | def_style_res = value.data; |
| 81 | } |
| 82 | } |
| 83 | } |
| 84 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 85 | // Now lock down the resource object and start pulling stuff from it. |
| 86 | res.lock(); |
Adam Lesinski | 1187590 | 2017-01-23 12:58:11 -0800 | [diff] [blame] | 87 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 88 | // Retrieve the default style bag, if requested. |
| 89 | const ResTable::bag_entry* def_style_start = nullptr; |
| 90 | uint32_t def_style_type_set_flags = 0; |
| 91 | ssize_t bag_off = def_style_res != 0 |
| 92 | ? res.getBagLocked(def_style_res, &def_style_start, |
| 93 | &def_style_type_set_flags) |
| 94 | : -1; |
| 95 | def_style_type_set_flags |= def_style_bag_type_set_flags; |
| 96 | const ResTable::bag_entry* const def_style_end = |
| 97 | def_style_start + (bag_off >= 0 ? bag_off : 0); |
| 98 | BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 99 | |
| 100 | // Now iterate through all of the attributes that the client has requested, |
| 101 | // filling in each with whatever data we can find. |
| 102 | for (size_t ii = 0; ii < attrs_length; ii++) { |
| 103 | const uint32_t cur_ident = attrs[ii]; |
| 104 | |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 105 | if (kDebugStyles) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 106 | ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 107 | } |
| 108 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 109 | ssize_t block = -1; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 110 | uint32_t type_set_flags = 0; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 111 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 112 | value.dataType = Res_value::TYPE_NULL; |
| 113 | value.data = Res_value::DATA_NULL_UNDEFINED; |
| 114 | config.density = 0; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 115 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 116 | // Try to find a value for this attribute... we prioritize values |
| 117 | // coming from, first XML attributes, then XML style, then default |
| 118 | // style, and finally the theme. |
| 119 | |
| 120 | // Retrieve the current input value if available. |
| 121 | if (src_values_length > 0 && src_values[ii] != 0) { |
| 122 | value.dataType = Res_value::TYPE_ATTRIBUTE; |
| 123 | value.data = src_values[ii]; |
| 124 | if (kDebugStyles) { |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 125 | ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, |
| 126 | value.data); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 127 | } |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 128 | } else { |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 129 | const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident); |
| 130 | if (def_style_entry != def_style_end) { |
| 131 | block = def_style_entry->stringBlock; |
| 132 | type_set_flags = def_style_type_set_flags; |
| 133 | value = def_style_entry->map.value; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 134 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 135 | ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 136 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 137 | } |
| 138 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 139 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 140 | uint32_t resid = 0; |
| 141 | if (value.dataType != Res_value::TYPE_NULL) { |
| 142 | // Take care of resolving the found resource to its final value. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 143 | ssize_t new_block = |
| 144 | theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); |
| 145 | if (new_block >= 0) block = new_block; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 146 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 147 | ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 148 | } |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 149 | } else if (value.data != Res_value::DATA_NULL_EMPTY) { |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 150 | // If we still don't have a value for this attribute, try to find |
| 151 | // it in the theme! |
| 152 | ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); |
| 153 | if (new_block >= 0) { |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 154 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 155 | ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 156 | } |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 157 | new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); |
| 158 | if (new_block >= 0) block = new_block; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 159 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 160 | ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 161 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 162 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 163 | } |
| 164 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 165 | // Deal with the special @null value -- it turns back to TYPE_NULL. |
| 166 | if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { |
| 167 | if (kDebugStyles) { |
| 168 | ALOGI("-> Setting to @null!"); |
| 169 | } |
| 170 | value.dataType = Res_value::TYPE_NULL; |
| 171 | value.data = Res_value::DATA_NULL_UNDEFINED; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 172 | block = -1; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 173 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 174 | |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 175 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 176 | ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 177 | } |
| 178 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 179 | // Write the final value back to Java. |
| 180 | out_values[STYLE_TYPE] = value.dataType; |
| 181 | out_values[STYLE_DATA] = value.data; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 182 | out_values[STYLE_ASSET_COOKIE] = |
| 183 | block != -1 ? static_cast<uint32_t>(res.getTableCookie(block)) |
| 184 | : static_cast<uint32_t>(-1); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 185 | out_values[STYLE_RESOURCE_ID] = resid; |
| 186 | out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; |
| 187 | out_values[STYLE_DENSITY] = config.density; |
| 188 | |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 189 | if (out_indices != nullptr && |
| 190 | (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 191 | indices_idx++; |
| 192 | out_indices[indices_idx] = ii; |
| 193 | } |
| 194 | |
| 195 | out_values += STYLE_NUM_ENTRIES; |
| 196 | } |
| 197 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 198 | res.unlock(); |
| 199 | |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 200 | if (out_indices != nullptr) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 201 | out_indices[0] = indices_idx; |
| 202 | } |
| 203 | return true; |
| 204 | } |
| 205 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 206 | void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr, |
| 207 | uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length, |
John Reck | f32adf4 | 2016-11-23 10:39:40 -0800 | [diff] [blame] | 208 | uint32_t* out_values, uint32_t* out_indices) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 209 | if (kDebugStyles) { |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 210 | ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", |
| 211 | theme, def_style_attr, def_style_res, xml_parser); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 212 | } |
| 213 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 214 | const ResTable& res = theme->getResTable(); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 215 | ResTable_config config; |
| 216 | Res_value value; |
| 217 | |
| 218 | int indices_idx = 0; |
| 219 | |
| 220 | // Load default style from attribute, if specified... |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 221 | uint32_t def_style_bag_type_set_flags = 0; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 222 | if (def_style_attr != 0) { |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 223 | Res_value value; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 224 | if (theme->getAttribute(def_style_attr, &value, |
| 225 | &def_style_bag_type_set_flags) >= 0) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 226 | if (value.dataType == Res_value::TYPE_REFERENCE) { |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 227 | def_style_res = value.data; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 228 | } |
| 229 | } |
| 230 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 231 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 232 | // Retrieve the style class associated with the current XML tag. |
| 233 | int style = 0; |
| 234 | uint32_t style_bag_type_set_flags = 0; |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 235 | if (xml_parser != nullptr) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 236 | ssize_t idx = xml_parser->indexOfStyle(); |
| 237 | if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) { |
| 238 | if (value.dataType == value.TYPE_ATTRIBUTE) { |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 239 | if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 240 | value.dataType = Res_value::TYPE_NULL; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 241 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 242 | } |
| 243 | if (value.dataType == value.TYPE_REFERENCE) { |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 244 | style = value.data; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 245 | } |
| 246 | } |
| 247 | } |
| 248 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 249 | // Now lock down the resource object and start pulling stuff from it. |
| 250 | res.lock(); |
Adam Lesinski | 1187590 | 2017-01-23 12:58:11 -0800 | [diff] [blame] | 251 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 252 | // Retrieve the default style bag, if requested. |
| 253 | const ResTable::bag_entry* def_style_attr_start = nullptr; |
| 254 | uint32_t def_style_type_set_flags = 0; |
| 255 | ssize_t bag_off = def_style_res != 0 |
| 256 | ? res.getBagLocked(def_style_res, &def_style_attr_start, |
| 257 | &def_style_type_set_flags) |
| 258 | : -1; |
| 259 | def_style_type_set_flags |= def_style_bag_type_set_flags; |
| 260 | const ResTable::bag_entry* const def_style_attr_end = |
| 261 | def_style_attr_start + (bag_off >= 0 ? bag_off : 0); |
| 262 | BagAttributeFinder def_style_attr_finder(def_style_attr_start, |
| 263 | def_style_attr_end); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 264 | |
| 265 | // Retrieve the style class bag, if requested. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 266 | const ResTable::bag_entry* style_attr_start = nullptr; |
| 267 | uint32_t style_type_set_flags = 0; |
| 268 | bag_off = |
| 269 | style != 0 |
| 270 | ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags) |
| 271 | : -1; |
| 272 | style_type_set_flags |= style_bag_type_set_flags; |
| 273 | const ResTable::bag_entry* const style_attr_end = |
| 274 | style_attr_start + (bag_off >= 0 ? bag_off : 0); |
| 275 | BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 276 | |
| 277 | // Retrieve the XML attributes, if requested. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 278 | static const ssize_t kXmlBlock = 0x10000000; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 279 | XmlAttributeFinder xml_attr_finder(xml_parser); |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 280 | const size_t xml_attr_end = |
| 281 | xml_parser != nullptr ? xml_parser->getAttributeCount() : 0; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 282 | |
| 283 | // Now iterate through all of the attributes that the client has requested, |
| 284 | // filling in each with whatever data we can find. |
| 285 | for (size_t ii = 0; ii < attrs_length; ii++) { |
| 286 | const uint32_t cur_ident = attrs[ii]; |
| 287 | |
| 288 | if (kDebugStyles) { |
| 289 | ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 290 | } |
| 291 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 292 | ssize_t block = kXmlBlock; |
| 293 | uint32_t type_set_flags = 0; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 294 | |
| 295 | value.dataType = Res_value::TYPE_NULL; |
| 296 | value.data = Res_value::DATA_NULL_UNDEFINED; |
| 297 | config.density = 0; |
| 298 | |
| 299 | // Try to find a value for this attribute... we prioritize values |
| 300 | // coming from, first XML attributes, then XML style, then default |
| 301 | // style, and finally the theme. |
| 302 | |
| 303 | // Walk through the xml attributes looking for the requested attribute. |
| 304 | const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident); |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 305 | if (xml_attr_idx != xml_attr_end) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 306 | // We found the attribute we were looking for. |
| 307 | xml_parser->getAttributeValue(xml_attr_idx, &value); |
| 308 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 309 | ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 310 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 311 | } |
| 312 | |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 313 | if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { |
| 314 | // Walk through the style class values looking for the requested attribute. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 315 | const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident); |
| 316 | if (style_attr_entry != style_attr_end) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 317 | // We found the attribute we were looking for. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 318 | block = style_attr_entry->stringBlock; |
| 319 | type_set_flags = style_type_set_flags; |
| 320 | value = style_attr_entry->map.value; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 321 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 322 | ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 323 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 324 | } |
| 325 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 326 | |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 327 | if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) { |
| 328 | // Walk through the default style values looking for the requested attribute. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 329 | const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident); |
| 330 | if (def_style_attr_entry != def_style_attr_end) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 331 | // We found the attribute we were looking for. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 332 | block = def_style_attr_entry->stringBlock; |
| 333 | type_set_flags = style_type_set_flags; |
| 334 | value = def_style_attr_entry->map.value; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 335 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 336 | ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 337 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 338 | } |
| 339 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 340 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 341 | uint32_t resid = 0; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 342 | if (value.dataType != Res_value::TYPE_NULL) { |
| 343 | // Take care of resolving the found resource to its final value. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 344 | ssize_t new_block = |
| 345 | theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config); |
| 346 | if (new_block >= 0) { |
| 347 | block = new_block; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 348 | } |
| 349 | |
| 350 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 351 | ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 352 | } |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 353 | } else if (value.data != Res_value::DATA_NULL_EMPTY) { |
| 354 | // If we still don't have a value for this attribute, try to find it in the theme! |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 355 | ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags); |
| 356 | if (new_block >= 0) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 357 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 358 | ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 359 | } |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 360 | new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config); |
| 361 | if (new_block >= 0) { |
| 362 | block = new_block; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 366 | ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 367 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 368 | } |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 369 | } |
| 370 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 371 | // Deal with the special @null value -- it turns back to TYPE_NULL. |
| 372 | if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { |
| 373 | if (kDebugStyles) { |
| 374 | ALOGI("-> Setting to @null!"); |
| 375 | } |
| 376 | value.dataType = Res_value::TYPE_NULL; |
| 377 | value.data = Res_value::DATA_NULL_UNDEFINED; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 378 | block = kXmlBlock; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 379 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 380 | |
| 381 | if (kDebugStyles) { |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 382 | ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 383 | } |
| 384 | |
| 385 | // Write the final value back to Java. |
| 386 | out_values[STYLE_TYPE] = value.dataType; |
| 387 | out_values[STYLE_DATA] = value.data; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 388 | out_values[STYLE_ASSET_COOKIE] = |
| 389 | block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block)) |
| 390 | : static_cast<uint32_t>(-1); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 391 | out_values[STYLE_RESOURCE_ID] = resid; |
| 392 | out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; |
| 393 | out_values[STYLE_DENSITY] = config.density; |
| 394 | |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 395 | if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 396 | indices_idx++; |
Adam Lesinski | 06d3e8f | 2017-01-05 17:03:55 -0800 | [diff] [blame] | 397 | |
| 398 | // out_indices must NOT be nullptr. |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 399 | out_indices[indices_idx] = ii; |
| 400 | } |
| 401 | |
| 402 | out_values += STYLE_NUM_ENTRIES; |
| 403 | } |
| 404 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 405 | res.unlock(); |
| 406 | |
Adam Lesinski | 06d3e8f | 2017-01-05 17:03:55 -0800 | [diff] [blame] | 407 | // out_indices must NOT be nullptr. |
| 408 | out_indices[0] = indices_idx; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 409 | } |
| 410 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 411 | bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, |
| 412 | uint32_t* attrs, size_t attrs_length, |
| 413 | uint32_t* out_values, uint32_t* out_indices) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 414 | ResTable_config config; |
| 415 | Res_value value; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 416 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 417 | int indices_idx = 0; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 418 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 419 | // Now lock down the resource object and start pulling stuff from it. |
| 420 | res->lock(); |
| 421 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 422 | // Retrieve the XML attributes, if requested. |
| 423 | const size_t xml_attr_count = xml_parser->getAttributeCount(); |
| 424 | size_t ix = 0; |
| 425 | uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 426 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 427 | static const ssize_t kXmlBlock = 0x10000000; |
| 428 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 429 | // Now iterate through all of the attributes that the client has requested, |
| 430 | // filling in each with whatever data we can find. |
| 431 | for (size_t ii = 0; ii < attrs_length; ii++) { |
| 432 | const uint32_t cur_ident = attrs[ii]; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 433 | ssize_t block = kXmlBlock; |
| 434 | uint32_t type_set_flags = 0; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 435 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 436 | value.dataType = Res_value::TYPE_NULL; |
| 437 | value.data = Res_value::DATA_NULL_UNDEFINED; |
| 438 | config.density = 0; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 439 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 440 | // Try to find a value for this attribute... |
| 441 | // Skip through XML attributes until the end or the next possible match. |
| 442 | while (ix < xml_attr_count && cur_ident > cur_xml_attr) { |
| 443 | ix++; |
| 444 | cur_xml_attr = xml_parser->getAttributeNameResID(ix); |
| 445 | } |
| 446 | // Retrieve the current XML attribute if it matches, and step to next. |
| 447 | if (ix < xml_attr_count && cur_ident == cur_xml_attr) { |
| 448 | xml_parser->getAttributeValue(ix, &value); |
| 449 | ix++; |
| 450 | cur_xml_attr = xml_parser->getAttributeNameResID(ix); |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 451 | } |
| 452 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 453 | uint32_t resid = 0; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 454 | if (value.dataType != Res_value::TYPE_NULL) { |
| 455 | // Take care of resolving the found resource to its final value. |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 456 | // printf("Resolving attribute reference\n"); |
| 457 | ssize_t new_block = res->resolveReference(&value, block, &resid, |
| 458 | &type_set_flags, &config); |
| 459 | if (new_block >= 0) block = new_block; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 460 | } |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 461 | |
| 462 | // Deal with the special @null value -- it turns back to TYPE_NULL. |
| 463 | if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { |
| 464 | value.dataType = Res_value::TYPE_NULL; |
| 465 | value.data = Res_value::DATA_NULL_UNDEFINED; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 466 | block = kXmlBlock; |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 467 | } |
| 468 | |
| 469 | // Write the final value back to Java. |
| 470 | out_values[STYLE_TYPE] = value.dataType; |
| 471 | out_values[STYLE_DATA] = value.data; |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 472 | out_values[STYLE_ASSET_COOKIE] = |
| 473 | block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block)) |
| 474 | : static_cast<uint32_t>(-1); |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 475 | out_values[STYLE_RESOURCE_ID] = resid; |
| 476 | out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags; |
| 477 | out_values[STYLE_DENSITY] = config.density; |
| 478 | |
Adam Lesinski | 32e7501 | 2017-05-09 15:25:37 -0700 | [diff] [blame] | 479 | if (out_indices != nullptr && |
| 480 | (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 481 | indices_idx++; |
| 482 | out_indices[indices_idx] = ii; |
| 483 | } |
| 484 | |
| 485 | out_values += STYLE_NUM_ENTRIES; |
| 486 | } |
| 487 | |
Adam Lesinski | bde1df2 | 2018-02-09 11:12:22 -0800 | [diff] [blame^] | 488 | res->unlock(); |
| 489 | |
Adam Lesinski | 4c67a47 | 2016-11-10 16:43:59 -0800 | [diff] [blame] | 490 | if (out_indices != nullptr) { |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 491 | out_indices[0] = indices_idx; |
| 492 | } |
| 493 | return true; |
Adam Lesinski | 4452e13 | 2016-10-12 07:47:28 -0700 | [diff] [blame] | 494 | } |
| 495 | |
Adam Lesinski | 7a37b74 | 2016-10-12 14:05:55 -0700 | [diff] [blame] | 496 | } // namespace android |