void Scheduler::uiManagerDidCreateShadowNode( const SharedShadowNode &shadowNode) { if (delegate_) { delegate_->schedulerDidRequestPreliminaryViewAllocation( shadowNode->getRootTag(), shadowNode->getComponentName()); } }
void UIManager::appendChild( const SharedShadowNode &parentShadowNode, const SharedShadowNode &childShadowNode) const { SystraceSection s("UIManager::appendChild"); auto &componentDescriptor = parentShadowNode->getComponentDescriptor(); componentDescriptor.appendChild(parentShadowNode, childShadowNode); }
void UIManager::setNativeProps( const SharedShadowNode &shadowNode, const RawProps &rawProps) const { SystraceSection s("UIManager::setNativeProps"); auto &componentDescriptor = shadowNode->getComponentDescriptor(); auto props = componentDescriptor.cloneProps(shadowNode->getProps(), rawProps); auto newShadowNode = shadowNode->clone({ /* .tag = */ ShadowNodeFragment::tagPlaceholder(), /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), /* .props = */ props, }); shadowTreeRegistry_->visit( shadowNode->getSurfaceId(), [&](const ShadowTree &shadowTree) { shadowTree.tryCommit( [&](const SharedRootShadowNode &oldRootShadowNode) { return oldRootShadowNode->clone(shadowNode, newShadowNode); }); }); }
SharedShadowNode UIManager::cloneNode( const SharedShadowNode &shadowNode, const SharedShadowNodeSharedList &children, const RawProps *rawProps) const { SystraceSection s("UIManager::cloneNode"); auto &componentDescriptor = shadowNode->getComponentDescriptor(); auto clonedShadowNode = componentDescriptor.cloneShadowNode( *shadowNode, { /* .tag = */ ShadowNodeFragment::tagPlaceholder(), /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), /* .props = */ rawProps ? componentDescriptor.cloneProps( shadowNode->getProps(), *rawProps) : ShadowNodeFragment::propsPlaceholder(), /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ children, }); return clonedShadowNode; }
void UIManager::updateState( const SharedShadowNode &shadowNode, const StateData::Shared &rawStateData) const { auto &componentDescriptor = shadowNode->getComponentDescriptor(); auto state = componentDescriptor.createState(shadowNode->getState(), rawStateData); auto newShadowNode = shadowNode->clone({ /* .tag = */ ShadowNodeFragment::tagPlaceholder(), /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), /* .props = */ ShadowNodeFragment::propsPlaceholder(), /* .eventEmitter = */ ShadowNodeFragment::eventEmitterPlaceholder(), /* .children = */ ShadowNodeFragment::childrenPlaceholder(), /* .localData = */ ShadowNodeFragment::localDataPlaceholder(), /* .state = */ state, }); shadowTreeRegistry_->visit( shadowNode->getSurfaceId(), [&](const ShadowTree &shadowTree) { shadowTree.tryCommit( [&](const SharedRootShadowNode &oldRootShadowNode) { return oldRootShadowNode->clone(shadowNode, newShadowNode); }); }); }
AttributedString BaseTextShadowNode::getAttributedString( const TextAttributes &textAttributes, const SharedShadowNode &parentNode) const { auto attributedString = AttributedString{}; for (const auto &childNode : parentNode->getChildren()) { // RawShadowNode auto rawTextShadowNode = std::dynamic_pointer_cast<const RawTextShadowNode>(childNode); if (rawTextShadowNode) { auto fragment = AttributedString::Fragment{}; fragment.string = rawTextShadowNode->getProps()->text; fragment.textAttributes = textAttributes; fragment.parentShadowNode = parentNode; attributedString.appendFragment(fragment); continue; } // TextShadowNode auto textShadowNode = std::dynamic_pointer_cast<const TextShadowNode>(childNode); if (textShadowNode) { auto localTextAttributes = textAttributes; localTextAttributes.apply(textShadowNode->getProps()->textAttributes); attributedString.appendAttributedString( textShadowNode->getAttributedString( localTextAttributes, textShadowNode)); continue; } // Any other kind of ShadowNode auto fragment = AttributedString::Fragment{}; fragment.shadowNode = childNode; fragment.textAttributes = textAttributes; attributedString.appendFragment(fragment); } return attributedString; }
const SharedComponentDescriptor ComponentDescriptorRegistry::operator[](const SharedShadowNode &shadowNode) const { ComponentHandle componentHandle = shadowNode->getComponentHandle(); return _registryByHandle.at(componentHandle); }
void calculateMutationInstructions( TreeMutationInstructionList &instructions, SharedShadowNode parentNode, SharedShadowNodeSharedList oldChildNodes, SharedShadowNodeSharedList newChildNodes ) { // The current version of the algorithm is otimized for simplicity, // not for performance of optimal result. // TODO(shergin): Consider to use Minimal Edit Distance algorithm to produce // optimal set of instructions and improve mounting performance. // https://en.wikipedia.org/wiki/Edit_distance // https://www.geeksforgeeks.org/dynamic-programming-set-5-edit-distance/ if (oldChildNodes == newChildNodes) { return; } if (oldChildNodes->size() == 0 && newChildNodes->size() == 0) { return; } std::unordered_set<Tag> insertedTags = {}; int index = 0; TreeMutationInstructionList createInstructions = {}; TreeMutationInstructionList deleteInstructions = {}; TreeMutationInstructionList insertInstructions = {}; TreeMutationInstructionList removeInstructions = {}; TreeMutationInstructionList replaceInstructions = {}; TreeMutationInstructionList downwardInstructions = {}; // Stage 1: Collectings Updates for (index = 0; index < oldChildNodes->size() && index < newChildNodes->size(); index++) { SharedShadowNode oldChildNode = oldChildNodes->at(index); SharedShadowNode newChildNode = newChildNodes->at(index); if (oldChildNode->getTag() != newChildNode->getTag()) { // Totally different nodes, updating is impossible. break; } if (*oldChildNode != *newChildNode) { replaceInstructions.push_back( TreeMutationInstruction::Replace( parentNode, oldChildNode, newChildNode, index ) ); } calculateMutationInstructions( downwardInstructions, oldChildNode, oldChildNode->getChildren(), newChildNode->getChildren() ); } int lastIndexAfterFirstStage = index; // Stage 2: Collectings Insertions for (; index < newChildNodes->size(); index++) { SharedShadowNode newChildNode = newChildNodes->at(index); insertInstructions.push_back( TreeMutationInstruction::Insert( parentNode, newChildNode, index ) ); insertedTags.insert(newChildNode->getTag()); SharedShadowNode newChildSourceNode = newChildNode->getSourceNode(); SharedShadowNodeSharedList newChildSourceChildNodes = newChildSourceNode ? newChildSourceNode->getChildren() : ShadowNode::emptySharedShadowNodeSharedList(); calculateMutationInstructions( downwardInstructions, newChildNode, newChildSourceChildNodes, newChildNode->getChildren() ); } // Stage 3: Collectings Deletions and Removals for (index = lastIndexAfterFirstStage; index < oldChildNodes->size(); index++) { SharedShadowNode oldChildNode = oldChildNodes->at(index); // Even if the old node was (re)inserted, we have to generate `remove` // instruction. removeInstructions.push_back( TreeMutationInstruction::Remove( parentNode, oldChildNode, index ) ); auto numberOfRemovedTags = insertedTags.erase(oldChildNode->getTag()); assert(numberOfRemovedTags == 0 || numberOfRemovedTags == 1); if (numberOfRemovedTags == 0) { // The old node was *not* (re)inserted, // so we have to generate `delete` instruction and apply the algorithm // recursively. deleteInstructions.push_back( TreeMutationInstruction::Delete( oldChildNode ) ); calculateMutationInstructions( downwardInstructions, oldChildNode, oldChildNode->getChildren(), ShadowNode::emptySharedShadowNodeSharedList() ); } } // Stage 4: Collectings Creations for (index = lastIndexAfterFirstStage; index < newChildNodes->size(); index++) { SharedShadowNode newChildNode = newChildNodes->at(index); if (insertedTags.find(newChildNode->getTag()) == insertedTags.end()) { // The new node was (re)inserted, so there is no need to create it. continue; } createInstructions.push_back( TreeMutationInstruction::Create( newChildNode ) ); } // All instructions in an optimal order: instructions.insert(instructions.end(), replaceInstructions.begin(), replaceInstructions.end()); instructions.insert(instructions.end(), removeInstructions.begin(), removeInstructions.end()); instructions.insert(instructions.end(), deleteInstructions.begin(), deleteInstructions.end()); instructions.insert(instructions.end(), createInstructions.begin(), createInstructions.end()); instructions.insert(instructions.end(), insertInstructions.begin(), insertInstructions.end()); instructions.insert(instructions.end(), downwardInstructions.begin(), downwardInstructions.end()); }