blob: 6935b24fe8780c840c4e2bf187039812f223cce2 [file] [log] [blame]
/**
* 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