| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| #include <math.h> |
| #include <cmath> |
| #include <utility> |
| |
| #include "core/common/view_utils.h" |
| #include "core/css/constants_name.h" |
| #include "core/render/manager/render_manager.h" |
| #include "core/render/node/factory/render_type.h" |
| #include "core/render/node/render_list.h" |
| #include "core/render/node/render_object.h" |
| #include "core/render/page/render_page.h" |
| #include "core/render/node/factory/render_creator.h" |
| |
| namespace WeexCore { |
| |
| RenderList::~RenderList() { |
| if (this->cell_slots_copys_.size() > 0) { |
| for (auto it = this->cell_slots_copys_.begin(); |
| it != this->cell_slots_copys_.end(); ++it) { |
| RenderObject *child = *it; |
| if (child) { |
| delete child; |
| child = nullptr; |
| } |
| } |
| this->cell_slots_copys_.clear(); |
| } |
| |
| if (this->cell_slots_.size() > 0) { |
| for (auto it = this->cell_slots_.begin(); it != this->cell_slots_.end(); |
| ++it) { |
| RenderObject *child = *it; |
| if (child) { |
| delete child; |
| child = nullptr; |
| } |
| } |
| this->cell_slots_.clear(); |
| } |
| } |
| |
| void RenderList::AddCellSlotCopyTrack(RenderObject *cell_slot) { |
| cell_slot->setParent(this, cell_slot); |
| this->cell_slots_copys_.push_back(cell_slot); |
| } |
| |
| std::map<std::string, std::string> *RenderList::GetDefaultStyle() { |
| std::map<std::string, std::string> *style = |
| new std::map<std::string, std::string>(); |
| |
| bool is_vertical = true; |
| RenderObject *parent = static_cast<RenderObject *>(getParent()); |
| |
| if (parent != nullptr && !parent->type().empty()) { |
| if (parent->type() == kHList) { |
| is_vertical = false; |
| } else if (TakeOrientation() == HORIZONTAL_VALUE) { |
| is_vertical = false; |
| } |
| } |
| |
| std::string prop = is_vertical ? HEIGHT : WIDTH; |
| |
| if (prop == HEIGHT && isnan(getStyleHeight()) && !this->is_set_flex_) { |
| this->is_set_flex_ = true; |
| style->insert(std::pair<std::string, std::string>(FLEX, "1")); |
| } else if (prop == WIDTH && isnan(TakeStyleWidth()) && !this->is_set_flex_) { |
| this->is_set_flex_ = true; |
| style->insert(std::pair<std::string, std::string>(FLEX, "1")); |
| } |
| |
| return style; |
| } |
| |
| void RenderList::set_flex(const float flex) { |
| this->is_set_flex_ = true; |
| WXCoreLayoutNode::set_flex(flex); |
| } |
| |
| std::map<std::string, std::string> *RenderList::GetDefaultAttr() { |
| if (!this->is_pre_calculate_cell_width_) { |
| PreCalculateCellWidth(); |
| } |
| return nullptr; |
| } |
| |
| void RenderList::PreCalculateCellWidth() { |
| std::map<std::string, std::string> *attrs = |
| new std::map<std::string, std::string>(); |
| if (attributes() != nullptr) { |
| this->column_count_ = TakeColumnCount(); |
| this->column_width_ = TakeColumnWidth(); |
| this->column_gap_ = TakeColumnGap(); |
| |
| this->left_gap_ = TakeLeftGap(); |
| this->right_gap_ = TakeRightGap(); |
| |
| this->available_width_ = |
| TakeStyleWidth() - |
| getWebPxByWidth(getPaddingLeft(), RenderManager::GetInstance()->viewport_width(page_id()), RenderManager::GetInstance()->DeviceWidth(page_id())) - |
| getWebPxByWidth(getPaddingRight(), RenderManager::GetInstance()->viewport_width(page_id()), RenderManager::GetInstance()->DeviceWidth(page_id())); |
| |
| if (AUTO_VALUE == this->column_count_ && |
| AUTO_VALUE == this->column_width_) { |
| this->column_count_ = COLUMN_COUNT_NORMAL; |
| this->column_width_ = (this->available_width_ - |
| ((this->column_count_ - 1) * this->column_gap_)) / |
| this->column_count_; |
| this->column_width_ = this->column_width_ > 0 ? this->column_width_ : 0; |
| } else if (AUTO_VALUE == this->column_width_ && |
| AUTO_VALUE != this->column_count_) { |
| this->column_width_ = |
| (this->available_width_ - this->left_gap_ - this->right_gap_ - |
| ((this->column_count_ - 1) * this->column_gap_)) / |
| this->column_count_; |
| this->column_width_ = this->column_width_ > 0 ? this->column_width_ : 0; |
| } else if (AUTO_VALUE != this->column_width_ && |
| AUTO_VALUE == this->column_count_) { |
| this->column_count_ = |
| static_cast<int>(round((this->available_width_ + this->column_gap_) / |
| (this->column_width_ + this->column_gap_) - |
| 0.5f)); |
| this->column_count_ = this->column_count_ > 0 ? this->column_count_ : 1; |
| if (this->column_count_ <= 0) { |
| this->column_count_ = COLUMN_COUNT_NORMAL; |
| } |
| this->column_width_ = ((this->available_width_ + this->column_gap_ - |
| this->left_gap_ - this->right_gap_) / |
| this->column_count_) - |
| this->column_gap_; |
| |
| } else if (AUTO_VALUE != this->column_width_ && |
| AUTO_VALUE != this->column_count_) { |
| int column_count = |
| static_cast<int>(round((this->available_width_ + this->column_gap_ - |
| this->left_gap_ - this->right_gap_) / |
| (this->column_width_ + this->column_gap_) - |
| 0.5f)); |
| this->column_count_ = |
| column_count > this->column_count_ ? this->column_count_ : column_count; |
| if (this->column_count_ <= 0) { |
| this->column_count_ = COLUMN_COUNT_NORMAL; |
| } |
| this->column_width_ = ((this->available_width_ + this->column_gap_ - |
| this->left_gap_ - this->right_gap_) / |
| this->column_count_) - |
| this->column_gap_; |
| } |
| |
| std::string span_offsets = CalculateSpanOffset(); |
| |
| this->is_pre_calculate_cell_width_ = true; |
| if (TakeColumnCount() > 0 || TakeColumnWidth() > 0 || |
| this->column_count_ >= COLUMN_COUNT_NORMAL) { |
| attrs->insert(std::pair<std::string, std::string>( |
| COLUMN_COUNT, to_string(this->column_count_))); |
| attrs->insert(std::pair<std::string, std::string>( |
| COLUMN_GAP, to_string(this->column_gap_))); |
| attrs->insert(std::pair<std::string, std::string>( |
| COLUMN_WIDTH, to_string(this->column_width_))); |
| } |
| if (span_offsets.length() > 0) { |
| attrs->insert(std::pair<std::string, std::string>( |
| SPAN_OFFSETS, to_string(span_offsets))); |
| } |
| |
| for (auto iter = attrs->cbegin(); iter != attrs->cend(); iter++) { |
| RenderObject::UpdateAttr(iter->first, iter->second); |
| } |
| } |
| |
| RenderPage *page = GetRenderPage(); |
| |
| if (page != nullptr) page->SendUpdateAttrAction(this, attrs); |
| |
| if (attrs != nullptr) { |
| attrs->clear(); |
| delete attrs; |
| attrs = nullptr; |
| } |
| } |
| |
| std::string RenderList::CalculateSpanOffset() { |
| std::string span_offsets; |
| float divide = available_width_ / column_count_; |
| float item_start_pos = 0; |
| if (this->left_gap_ > 0 || this->right_gap_ > 0 || column_gap_ > 0) { |
| span_offsets.append("["); |
| for (int i = 0; i < this->column_count_; i++) { |
| if (i == 0) { |
| item_start_pos += left_gap_; |
| } else { |
| item_start_pos += column_gap_ + column_width_; |
| } |
| float span_offset = item_start_pos - i * divide; |
| span_offsets.append(to_string(span_offset)); |
| if (i != this->column_count_ - 1) { |
| span_offsets.append(","); |
| } |
| } |
| span_offsets.append("]"); |
| } |
| return span_offsets; |
| } |
| |
| float RenderList::TakeStyleWidth() { |
| float width = |
| getWebPxByWidth(getLayoutWidth(), RenderManager::GetInstance()->viewport_width(page_id()), RenderManager::GetInstance()->DeviceWidth(page_id())); |
| if (isnan(width) || width <= 0) { |
| if (getParent() != nullptr) { |
| width = getWebPxByWidth(getParent()->getLayoutWidth(), |
| RenderManager::GetInstance()->viewport_width(page_id()), RenderManager::GetInstance()->DeviceWidth(page_id())); |
| } |
| if (isnan(width) || width <= 0) { |
| width = getWebPxByWidth(RenderObject::getStyleWidth(), |
| RenderManager::GetInstance()->viewport_width(page_id()), RenderManager::GetInstance()->DeviceWidth(page_id())); |
| } |
| } |
| if (isnan(width) || width <= 0) { |
| width = RenderManager::GetInstance()->viewport_width(page_id()); |
| } |
| return width; |
| } |
| |
| int RenderList::AddRenderObject(int index, RenderObject *child) { |
| if (type() == kRenderRecycleList && |
| (child->type() == kRenderCellSlot || child->type() == kRenderCell || |
| child->type() == kRenderHeader)) { |
| child->setParent(this, child); |
| this->cell_slots_.insert(this->cell_slots_.end(), child); |
| index = -1; |
| } else { |
| index = RenderObject::AddRenderObject(index, child); |
| } |
| |
| if (!this->is_pre_calculate_cell_width_) { |
| PreCalculateCellWidth(); |
| } |
| |
| if (this->column_width_ != 0 && !isnan(this->column_width_)) { |
| AddRenderObjectWidth(child, false); |
| } |
| return index; |
| } |
| |
| void RenderList::AddRenderObjectWidth(RenderObject *child, |
| const bool updating) { |
| if ((RenderCreator::GetInstance()->IsAffineType(type(), kRenderWaterfall)) || type() == kRenderRecycleList) { |
| if (child->type() == kRenderHeader || child->type() == kRenderFooter) { |
| child->ApplyStyle(WIDTH, to_string(this->available_width_), updating); |
| } else if (child->is_sticky()) { |
| child->ApplyStyle(WIDTH, to_string(this->available_width_), updating); |
| } else if (child->type() == kRenderCell || |
| child->type() == kRenderCellSlot) { |
| child->ApplyStyle(WIDTH, to_string(this->column_width_), updating); |
| } |
| } |
| } |
| |
| |
| void RenderList::AddAttr(std::string key, std::string value) { |
| MapInsertOrAssign(&mOriginalAttrs, key, value); |
| RenderObject::AddAttr(key, value); |
| } |
| |
| |
| void RenderList::UpdateAttr(std::string key, std::string value) { |
| MapInsertOrAssign(&mOriginalAttrs, key, value); |
| RenderObject::UpdateAttr(key, value); |
| |
| if (!GetAttr(COLUMN_COUNT).empty() || !GetAttr(COLUMN_GAP).empty() || |
| !GetAttr(COLUMN_WIDTH).empty()) { |
| PreCalculateCellWidth(); |
| |
| if (this->column_width_ == 0 && isnan(this->column_width_)) { |
| return; |
| } |
| |
| Index count = getChildCount(); |
| for (Index i = 0; i < count; i++) { |
| RenderObject *child = GetChild(i); |
| AddRenderObjectWidth(child, true); |
| } |
| } |
| } |
| |
| static const std::string GetMapAttr(std::map<std::string,std::string>* attrs, const std::string &key) { |
| if (attrs == nullptr) return ""; |
| std::map<std::string, std::string>::iterator iter = attrs->find(key); |
| if (iter != attrs->end()) { |
| return iter->second; |
| } else { |
| return ""; |
| } |
| } |
| |
| float RenderList::TakeColumnCount() { |
| std::string column_count = GetMapAttr(&mOriginalAttrs, COLUMN_COUNT); |
| |
| if (column_count.empty() || column_count == AUTO) { |
| return AUTO_VALUE; |
| } |
| |
| float column_count_value = getFloat(column_count.c_str()); |
| return (column_count_value > 0 && !isnan(column_count_value)) ? column_count_value |
| : AUTO_VALUE; |
| } |
| |
| float RenderList::TakeColumnGap() { |
| std::string column_gap = GetMapAttr(&mOriginalAttrs, COLUMN_GAP); |
| |
| if (column_gap.empty() || column_gap == NORMAL) { |
| return COLUMN_GAP_NORMAL; |
| } |
| |
| float column_gap_value = getFloat(column_gap.c_str()); |
| return (column_gap_value > 0 && !isnan(column_gap_value)) ? column_gap_value |
| : AUTO_VALUE; |
| } |
| |
| float RenderList::TakeColumnWidth() { |
| std::string column_width = GetMapAttr(&mOriginalAttrs, COLUMN_WIDTH); |
| |
| if (column_width.empty() || column_width == AUTO) { |
| return AUTO_VALUE; |
| } |
| |
| float column_width_value = getFloat(column_width.c_str()); |
| return (column_width_value > 0 && !isnan(column_width_value)) ? column_width_value |
| : 0; |
| } |
| |
| float RenderList::TakeLeftGap() { |
| std::string left_gap =GetMapAttr(&mOriginalAttrs, LEFT_GAP); |
| |
| if (left_gap.empty() || left_gap == AUTO) { |
| return 0; |
| } |
| |
| float left_gap_value = getFloat(left_gap.c_str()); |
| return (left_gap_value > 0 && !isnan(left_gap_value)) ? left_gap_value : 0; |
| } |
| |
| float RenderList::TakeRightGap() { |
| std::string right_gap =GetMapAttr(&mOriginalAttrs, RIGHT_GAP); |
| |
| if (right_gap.empty() || right_gap == AUTO) { |
| return 0; |
| } |
| |
| float right_gap_value = getFloat(right_gap.c_str()); |
| return (right_gap_value > 0 && !isnan(right_gap_value)) ? right_gap_value : 0; |
| } |
| |
| int RenderList::TakeOrientation() { |
| std::string direction = GetAttr(SCROLL_DIRECTION); |
| if (HORIZONTAL == direction) { |
| return HORIZONTAL_VALUE; |
| } |
| return VERTICAL_VALUE; |
| } |
| } // namespace WeexCore |