blob: ff03197b16dd11b2bbed24621e510d1d1cad6c02 [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 "core/render/node/render_object.h"
#include <math.h>
#include "core/common/view_utils.h"
#include "core/css/constants_name.h"
#include "core/css/constants_value.h"
#include "core/css/css_value_getter.h"
#include "core/layout/layout.h"
#include "core/manager/weex_core_manager.h"
#include "core/render/manager/render_manager.h"
#include "core/render/page/render_page.h"
namespace WeexCore {
RenderObject::RenderObject() : parent_render_(nullptr) {
this->styles_ = new std::map<std::string, std::string>();
this->attributes_ = new std::map<std::string, std::string>();
this->events_ = new std::set<std::string>();
this->is_root_render_ = false;
}
RenderObject::~RenderObject() {
this->parent_render_ = nullptr;
if (this->styles_ != nullptr) {
delete this->styles_;
this->styles_ = nullptr;
}
if (this->attributes_ != nullptr) {
delete this->attributes_;
this->attributes_ = nullptr;
}
if (this->events_ != nullptr) {
delete this->events_;
this->events_ = nullptr;
}
for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
RenderObject *child = static_cast<RenderObject *>(*it);
if (child != nullptr) {
delete child;
}
}
}
void RenderObject::ApplyDefaultStyle(bool reserve) {
std::map<std::string, std::string> *style = GetDefaultStyle();
if (style == nullptr) return;
for (auto iter = style->cbegin(); iter != style->cend(); iter++)
AddStyle(iter->first, iter->second, reserve);
if (style != nullptr) {
delete style;
}
}
void RenderObject::ApplyDefaultAttr() {
std::map<std::string, std::string> *attrs = GetDefaultAttr();
if (attrs == nullptr) return;
for (auto iter = attrs->cbegin(); iter != attrs->cend(); iter++) {
UpdateAttr(iter->first, iter->second);
}
if (attrs != nullptr) {
delete attrs;
}
}
static WXCoreSize measureFunc_Impl(WXCoreLayoutNode *node, float width,
MeasureMode widthMeasureMode, float height,
MeasureMode heightMeasureMode) {
WXCoreSize size;
size.height = 0;
size.width = 0;
if (!node->haveMeasureFunc()) return size;
return WeexCoreManager::Instance()
->getPlatformBridge()
->platform_side()
->InvokeMeasureFunction(
static_cast<RenderObject *>(node)->page_id().c_str(),
reinterpret_cast<intptr_t>(node), width, widthMeasureMode, height,
heightMeasureMode);
}
void RenderObject::BindMeasureFunc() { setMeasureFunc(measureFunc_Impl); }
void RenderObject::OnLayoutBefore() {
if (!haveMeasureFunc()) return;
WeexCoreManager::Instance()
->getPlatformBridge()
->platform_side()
->InvokeLayoutBefore(page_id().c_str(), reinterpret_cast<intptr_t>(this));
}
void RenderObject::OnLayoutPlatform() {
if (!getNeedsPlatformDependentLayout()) return;
WeexCoreManager::Instance()
->getPlatformBridge()
->platform_side()
->InvokeLayoutPlatform(page_id().c_str(), reinterpret_cast<intptr_t>(this));
}
void RenderObject::OnLayoutAfter(float width, float height) {
if (!haveMeasureFunc()) return;
WeexCoreManager::Instance()
->getPlatformBridge()
->platform_side()
->InvokeLayoutAfter(page_id().c_str(), reinterpret_cast<intptr_t>(this),
width, height);
}
StyleType RenderObject::ApplyStyle(const std::string &key,
const std::string &value,
const bool updating) {
bool insert = false;
if (value.length() > 0 && (value.at(0) == JSON_OBJECT_MARK_CHAR ||
value.at(0) == JSON_ARRAY_MARK_CHAR)) {
MapInsertOrAssign(this->styles_, key, value);
insert = true;
}
if (key == ALIGN_ITEMS) {
setAlignItems(GetWXCoreAlignItem(value));
return kTypeLayout;
} else if (key == ALIGN_SELF) {
setAlignSelf(GetWXCoreAlignSelf(value));
return kTypeLayout;
} else if (key == FLEX) {
if (value.empty()) {
set_flex(0);
} else {
float ret = getFloat(value.c_str());
if (!isnan(ret)) {
set_flex(ret);
}
}
return kTypeLayout;
} else if (key == DIRECTION) {
WeexCore::WXCoreDirection direction = GetWXCoreDirection(value);
if (direction == WeexCore::kDirectionInherit && this->is_root_render_ ) {
direction = WeexCore::kDirectionLTR;
}
setDirection(direction, updating);
return kTypeInheritableLayout;
} else if (key == FLEX_DIRECTION) {
setFlexDirection(GetWXCoreFlexDirection(value), updating);
return kTypeLayout;
} else if (key == JUSTIFY_CONTENT) {
setJustifyContent(GetWXCoreJustifyContent(value));
return kTypeLayout;
} else if (key == FLEX_WRAP) {
setFlexWrap(GetWXCoreFlexWrap(value));
return kTypeLayout;
} else if (key == MIN_WIDTH) {
UpdateStyleInternal(key, value, NAN,
[=](float foo) { setMinWidth(foo, updating); });
return kTypeLayout;
} else if (key == MIN_HEIGHT) {
UpdateStyleInternal(key, value, NAN, [=](float foo) { setMinHeight(foo); });
return kTypeLayout;
} else if (key == MAX_WIDTH) {
UpdateStyleInternal(key, value, NAN,
[=](float foo) { setMaxWidth(foo, updating); });
return kTypeLayout;
} else if (key == MAX_HEIGHT) {
UpdateStyleInternal(key, value, NAN, [=](float foo) { setMaxHeight(foo); });
return kTypeLayout;
} else if (key == HEIGHT) {
if (UpdateStyleInternal(key, value, NAN,
[=](float foo) { setStyleHeight(foo); })) {
setStyleHeightLevel(CSS_STYLE);
}
return kTypeLayout;
} else if (key == WIDTH) {
if (UpdateStyleInternal(key, value, NAN,
[=](float foo) { setStyleWidth(foo, updating); })) {
setStyleWidthLevel(CSS_STYLE);
}
return kTypeLayout;
} else if (key == POSITION) {
setStylePositionType(GetWXCorePositionType(value));
if (value == STICKY) {
this->is_sticky_ = true;
}
MapInsertOrAssign(this->styles_, key, value);
return kTypeStyle;
} else if (key == LEFT) {
UpdateStyleInternal(key, value, NAN, [=](float foo) {
setStylePosition(kPositionEdgeLeft, foo);
});
return kTypeLayout;
} else if (key == TOP) {
UpdateStyleInternal(key, value, NAN, [=](float foo) {
setStylePosition(kPositionEdgeTop, foo);
});
return kTypeLayout;
} else if (key == RIGHT) {
UpdateStyleInternal(key, value, NAN, [=](float foo) {
setStylePosition(kPositionEdgeRight, foo);
});
return kTypeLayout;
} else if (key == BOTTOM) {
UpdateStyleInternal(key, value, NAN, [=](float foo) {
setStylePosition(kPositionEdgeBottom, foo);
});
return kTypeLayout;
} else if (key == MARGIN) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setMargin(kMarginALL, foo); });
return kTypeMargin;
} else if (key == MARGIN_LEFT) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setMargin(kMarginLeft, foo); });
return kTypeMargin;
} else if (key == MARGIN_TOP) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setMargin(kMarginTop, foo); });
return kTypeMargin;
} else if (key == MARGIN_RIGHT) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setMargin(kMarginRight, foo); });
return kTypeMargin;
} else if (key == MARGIN_BOTTOM) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setMargin(kMarginBottom, foo); });
return kTypeMargin;
} else if (key == BORDER_WIDTH) {
UpdateStyleInternal(key, value, 0, [=](float foo) {
setBorderWidth(kBorderWidthALL, foo);
});
return kTypeBorder;
} else if (key == BORDER_TOP_WIDTH) {
UpdateStyleInternal(key, value, 0, [=](float foo) {
setBorderWidth(kBorderWidthTop, foo);
});
return kTypeBorder;
} else if (key == BORDER_RIGHT_WIDTH) {
UpdateStyleInternal(key, value, 0, [=](float foo) {
setBorderWidth(kBorderWidthRight, foo);
});
return kTypeBorder;
} else if (key == BORDER_BOTTOM_WIDTH) {
UpdateStyleInternal(key, value, 0, [=](float foo) {
setBorderWidth(kBorderWidthBottom, foo);
});
return kTypeBorder;
} else if (key == BORDER_LEFT_WIDTH) {
UpdateStyleInternal(key, value, 0, [=](float foo) {
setBorderWidth(kBorderWidthLeft, foo);
});
return kTypeBorder;
} else if (key == PADDING) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setPadding(kPaddingALL, foo); });
return kTypePadding;
} else if (key == PADDING_LEFT) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setPadding(kPaddingLeft, foo); });
return kTypePadding;
} else if (key == PADDING_TOP) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setPadding(kPaddingTop, foo); });
return kTypePadding;
} else if (key == PADDING_RIGHT) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setPadding(kPaddingRight, foo); });
return kTypePadding;
} else if (key == PADDING_BOTTOM) {
UpdateStyleInternal(key, value, 0,
[=](float foo) { setPadding(kPaddingBottom, foo); });
return kTypePadding;
} else {
if (!insert) {
MapInsertOrAssign(this->styles_, key, value);
}
return kTypeStyle;
}
}
const std::string RenderObject::GetStyle(const std::string &key) {
if (this->styles_ == nullptr) return "";
std::map<std::string, std::string>::iterator iter = this->styles_->find(key);
if (iter != this->styles_->end()) {
return iter->second;
} else {
return "";
}
}
const std::string RenderObject::GetAttr(const std::string &key) {
if (this->attributes_ == nullptr) return "";
std::map<std::string, std::string>::iterator iter =
this->attributes_->find(key);
if (iter != this->attributes_->end()) {
return iter->second;
} else {
return "";
}
}
int RenderObject::AddRenderObject(int index, RenderObject *child) {
if (child == nullptr || index < -1) {
return index;
}
Index count = getChildCount();
index = index >= count ? -1 : index;
if (index == -1) {
addChildAt(child, getChildCount());
} else {
addChildAt(child, index);
}
child->set_parent_render(this);
return index;
}
Index RenderObject::IndexOf(const RenderObject *render) {
if (render == nullptr) {
return -1;
} else {
int i = 0;
for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
RenderObject *child = static_cast<RenderObject *>(*it);
if (child != nullptr) {
if (render->ref() == child->ref()) return i;
}
++i;
}
}
return -1;
}
bool RenderObject::UpdateStyleInternal(const std::string key,
const std::string value, float fallback,
std::function<void(float)> functor) {
bool ret = false;
if (value.empty()) {
functor(fallback);
ret = true;
} else {
float fvalue = getFloatByViewport(value,
RenderManager::GetInstance()->viewport_width(page_id()),
RenderManager::GetInstance()->DeviceWidth(page_id()),
#if OS_IOS
// reduce a map search on iOS
false
#else
RenderManager::GetInstance()->round_off_deviation(page_id())
#endif
);
if (!isnan(fvalue)) {
functor(fvalue);
ret = true;
}
}
return ret;
}
void RenderObject::LayoutBeforeImpl() {
if (isDirty()) {
OnLayoutBefore();
}
for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
RenderObject *child = static_cast<RenderObject *>(*it);
if (child != nullptr) {
child->LayoutBeforeImpl();
}
}
}
void RenderObject::LayoutPlatformImpl() {
if (hasNewLayout()) {
OnLayoutPlatform();
}
for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
RenderObject *child = static_cast<RenderObject *>(*it);
if (child != nullptr) {
child->LayoutPlatformImpl();
}
}
}
void RenderObject::LayoutAfterImpl() {
if (hasNewLayout()) {
OnLayoutAfter(getLayoutWidth(), getLayoutHeight());
}
for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
RenderObject *child = static_cast<RenderObject *>(*it);
if (child != nullptr) {
child->LayoutAfterImpl();
}
}
}
void RenderObject::CopyFrom(RenderObject *src) {
IRenderObject::CopyFrom(src);
this->styles_->insert(src->styles_->begin(), src->styles_->end());
this->attributes_->insert(src->attributes_->begin(), src->attributes_->end());
this->events_->insert(src->events_->begin(), src->events_->end());
}
void RenderObject::MapInsertOrAssign(
std::map<std::string, std::string> *targetMap, const std::string &key,
const std::string &value) {
std::map<std::string, std::string>::iterator it = targetMap->find(key);
if (it != targetMap->end()) {
it->second = value;
} else {
targetMap->insert({key, value});
}
}
bool RenderObject::ViewInit() {
return (!isnan(getStyleWidth()) && getStyleWidth() > 0) ||
(is_root_render() && GetRenderPage() != nullptr &&
GetRenderPage()->is_render_container_width_wrap_content());
}
RenderPage *RenderObject::GetRenderPage() {
return static_cast<RenderPage*>(RenderManager::GetInstance()->GetPage(page_id()));
}
bool RenderObject::IsAppendTree() {
std::string append = GetAttr(APPEND);
if (append == "tree") {
return true;
}
return false;
}
void RenderObject::UpdateAttr(std::string key, std::string value) {
MapInsertOrAssign(this->attributes_, key, value);
}
StyleType RenderObject::UpdateStyle(std::string key, std::string value) {
return ApplyStyle(key, value, true);
}
void RenderObject::MergeStyles(std::vector<std::pair<std::string, std::string>> *src) {
if (src) {
for (auto& p : *src) {
MapInsertOrAssign(styles_, p.first, p.second);
}
}
}
RenderObject *RenderObject::GetChild(const Index &index) {
return static_cast<RenderObject *>(getChildAt(index));
}
void RenderObject::RemoveRenderObject(RenderObject *child) {
removeChild(child);
}
void RenderObject::AddAttr(std::string key, std::string value) {
MapInsertOrAssign(this->attributes_, key, value);
}
StyleType RenderObject::AddStyle(std::string key, std::string value, bool reserve) {
if (reserve) {
MapInsertOrAssign(styles_, key, value);
}
return ApplyStyle(key, value, false);
}
void RenderObject::AddEvent(std::string event) {
if (this->events_ == nullptr) {
this->events_ = new std::set<std::string>();
}
this->events_->insert(event);
}
void RenderObject::RemoveEvent(const std::string &event) {
this->events_->erase(event);
}
} // namespace WeexCore