• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "recording/draw_cmd_list.h"
17 
18 #include <cstddef>
19 #include <memory>
20 
21 #include "recording/draw_cmd.h"
22 #include "recording/recording_canvas.h"
23 #include "utils/log.h"
24 #include "utils/performanceCaculate.h"
25 
26 namespace OHOS {
27 namespace Rosen {
28 namespace Drawing {
29 namespace {
30     constexpr uint32_t DRAWCMDLIST_OPSIZE_COUNT_LIMIT = 50000;
31 }
32 
CreateFromData(const CmdListData & data,bool isCopy)33 std::shared_ptr<DrawCmdList> DrawCmdList::CreateFromData(const CmdListData& data, bool isCopy)
34 {
35     auto cmdList = std::make_shared<DrawCmdList>(DrawCmdList::UnmarshalMode::DEFERRED);
36     if (isCopy) {
37         cmdList->opAllocator_.BuildFromDataWithCopy(data.first, data.second);
38     } else {
39         cmdList->opAllocator_.BuildFromData(data.first, data.second);
40     }
41 
42     int32_t* width = static_cast<int32_t*>(cmdList->opAllocator_.OffsetToAddr(0, sizeof(int32_t)));
43     int32_t* height = static_cast<int32_t*>(cmdList->opAllocator_.OffsetToAddr(sizeof(int32_t), sizeof(int32_t)));
44     if (width && height) {
45         cmdList->width_ = *width;
46         cmdList->height_ = *height;
47     } else {
48         cmdList->width_ = 0;
49         cmdList->height_ = 0;
50     }
51     return cmdList;
52 }
53 
DrawCmdList(DrawCmdList::UnmarshalMode mode)54 DrawCmdList::DrawCmdList(DrawCmdList::UnmarshalMode mode) : width_(0), height_(0), mode_(mode) {}
55 
DrawCmdList(int32_t width,int32_t height,DrawCmdList::UnmarshalMode mode)56 DrawCmdList::DrawCmdList(int32_t width, int32_t height, DrawCmdList::UnmarshalMode mode)
57     : width_(width), height_(height), mode_(mode)
58 {
59     opAllocator_.Add(&width_, sizeof(int32_t));
60     opAllocator_.Add(&height_, sizeof(int32_t));
61 }
62 
~DrawCmdList()63 DrawCmdList::~DrawCmdList()
64 {
65     if (drawOpItems_.size() == 0 && isNeedUnmarshalOnDestruct_) {
66         UnmarshallingDrawOps();
67     }
68     ClearOp();
69 }
70 
AddDrawOp(std::shared_ptr<DrawOpItem> && drawOpItem)71 bool DrawCmdList::AddDrawOp(std::shared_ptr<DrawOpItem>&& drawOpItem)
72 {
73     if (mode_ != DrawCmdList::UnmarshalMode::DEFERRED) {
74         return false;
75     }
76     std::lock_guard<std::recursive_mutex> lock(mutex_);
77     drawOpItems_.emplace_back(drawOpItem);
78     return true;
79 }
80 
ClearOp()81 void DrawCmdList::ClearOp()
82 {
83     {
84         std::lock_guard<std::recursive_mutex> lock(mutex_);
85         opAllocator_.ClearData();
86         opAllocator_.Add(&width_, sizeof(int32_t));
87         opAllocator_.Add(&height_, sizeof(int32_t));
88         imageAllocator_.ClearData();
89         bitmapAllocator_.ClearData();
90         imageMap_.clear();
91         imageHandleVec_.clear();
92         drawOpItems_.clear();
93         lastOpGenSize_ = 0;
94         lastOpItemOffset_ = std::nullopt;
95         opCnt_ = 0;
96     }
97     {
98         std::lock_guard<std::mutex> lock(recordCmdMutex_);
99         recordCmdVec_.clear();
100     }
101     {
102         std::lock_guard<std::mutex> lock(imageObjectMutex_);
103         imageObjectVec_.clear();
104     }
105     {
106         std::lock_guard<std::mutex> lock(imageBaseObjMutex_);
107         imageBaseObjVec_.clear();
108     }
109 }
110 
GetWidth() const111 int32_t DrawCmdList::GetWidth() const
112 {
113     return width_;
114 }
115 
GetHeight() const116 int32_t DrawCmdList::GetHeight() const
117 {
118     return height_;
119 }
120 
SetWidth(int32_t width)121 void DrawCmdList::SetWidth(int32_t width)
122 {
123     width_ = width;
124 }
125 
SetHeight(int32_t height)126 void DrawCmdList::SetHeight(int32_t height)
127 {
128     height_ = height;
129 }
130 
GetNoNeedUICaptured() const131 bool DrawCmdList::GetNoNeedUICaptured() const
132 {
133     return noNeedUICaptured_;
134 }
135 
SetNoNeedUICaptured(bool noNeedUICaptured)136 void DrawCmdList::SetNoNeedUICaptured(bool noNeedUICaptured)
137 {
138     noNeedUICaptured_ = noNeedUICaptured;
139 }
140 
IsEmpty() const141 bool DrawCmdList::IsEmpty() const
142 {
143     if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
144         return drawOpItems_.empty();
145     }
146     size_t offset = 2 * sizeof(int32_t); // 2 is width and height.Offset of first OpItem is behind the w and h
147     if (opAllocator_.GetSize() <= offset && drawOpItems_.size() == 0) {
148         return true;
149     }
150     return false;
151 }
152 
GetOpItemSize() const153 size_t DrawCmdList::GetOpItemSize() const
154 {
155     return mode_ == DrawCmdList::UnmarshalMode::DEFERRED ? drawOpItems_.size() : opCnt_;
156 }
157 
GetOpsWithDesc() const158 std::string DrawCmdList::GetOpsWithDesc() const
159 {
160     std::string desc;
161     for (auto& item : drawOpItems_) {
162         if (item == nullptr) {
163             continue;
164         }
165         desc += item->GetOpDesc();
166         desc += "\n";
167     }
168     LOGD("DrawCmdList::GetOpsWithDesc %{public}s, opitem sz: %{public}zu", desc.c_str(), drawOpItems_.size());
169     return desc;
170 }
171 
Dump(std::string & out)172 void DrawCmdList::Dump(std::string& out)
173 {
174     bool found = false;
175     std::lock_guard<std::recursive_mutex> lock(mutex_);
176     for (auto& item : drawOpItems_) {
177         if (item == nullptr) {
178             continue;
179         }
180         found = true;
181         item->Dump(out);
182         out += ' ';
183     }
184     if (found) {
185         out.pop_back();
186     }
187 }
188 
MarshallingDrawOps()189 void DrawCmdList::MarshallingDrawOps()
190 {
191     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
192         return;
193     }
194     std::lock_guard<std::recursive_mutex> lock(mutex_);
195     if (replacedOpListForVector_.empty()) {
196         for (auto& op : drawOpItems_) {
197             if (op) {
198                 op->Marshalling(*this);
199             }
200         }
201         return;
202     }
203     for (auto& [index, op] : replacedOpListForVector_) {
204         op.swap(drawOpItems_[index]);
205     }
206     std::vector<uint32_t> opIndexForCache(replacedOpListForVector_.size());
207     uint32_t opReplaceIndex = 0;
208     for (auto index = 0u; index < drawOpItems_.size(); ++index) {
209         if (drawOpItems_[index]) {
210             drawOpItems_[index]->Marshalling(*this);
211         }
212         if (index == static_cast<size_t>(replacedOpListForVector_[opReplaceIndex].first)) {
213             opIndexForCache[opReplaceIndex] = lastOpItemOffset_.value();
214             ++opReplaceIndex;
215         }
216     }
217     for (auto index = 0u; index < replacedOpListForVector_.size(); ++index) {
218         if (replacedOpListForVector_[index].second) {
219             replacedOpListForVector_[index].second->Marshalling(*this);
220         }
221         replacedOpListForBuffer_.emplace_back(opIndexForCache[index], lastOpItemOffset_.value());
222     }
223 }
224 
CaculatePerformanceOpType()225 void DrawCmdList::CaculatePerformanceOpType()
226 {
227     size_t offset = offset_;
228     const int caculatePerformaceCount = 500;    // 被测单接口用例至少出现500次以上
229     std::map<uint32_t, uint32_t> opTypeCountMap;
230     uint32_t count = 0;
231     do {
232         count++;
233         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
234         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
235         if (curOpItemPtr == nullptr) {
236             break;
237         }
238         uint32_t type = curOpItemPtr->GetType();
239         if (opTypeCountMap.find(type) != opTypeCountMap.end()) {
240             if (++opTypeCountMap[type] > caculatePerformaceCount) {
241                 performanceCaculateOpType_ = type;
242                 DRAWING_PERFORMANCE_START_CACULATE;
243                 return;
244             }
245         } else {
246             opTypeCountMap[type] = 1;   // 记录出现的第1次
247         }
248         if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
249             break;
250         }
251         offset = curOpItemPtr->GetNextOpItemOffset();
252     } while (offset != 0 && count <= MAX_OPITEMSIZE);
253 }
254 
UnmarshallingDrawOps(uint32_t * opItemCount)255 void DrawCmdList::UnmarshallingDrawOps(uint32_t* opItemCount)
256 {
257     if (PerformanceCaculate::GetDrawingTestRecordingEnabled()) {
258         CaculatePerformanceOpType();
259     }
260     if (performanceCaculateOpType_ != 0) {
261         LOGI("Drawing Performance UnmarshallingDrawOps begin %{public}lld", PerformanceCaculate::GetUpTime());
262     }
263 
264     if (opAllocator_.GetSize() <= offset_ || width_ <= 0 || height_ <= 0) {
265         return;
266     }
267 
268     UnmarshallingPlayer player = { *this };
269     drawOpItems_.clear();
270     lastOpGenSize_ = 0;
271     uint32_t opReplaceIndex = 0;
272     size_t offset = offset_;
273     uint32_t count = 0;
274     do {
275         count++;
276         if (opItemCount && ++(*opItemCount) > MAX_OPITEMSIZE) {
277             break;
278         }
279         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
280         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
281         if (curOpItemPtr == nullptr) {
282             LOGE("DrawCmdList::UnmarshallingOps failed, opItem is nullptr");
283             break;
284         }
285         uint32_t type = curOpItemPtr->GetType();
286         auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset);
287         if (!op) {
288             if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
289                 break;
290             }
291             offset = curOpItemPtr->GetNextOpItemOffset();
292             continue;
293         }
294         if (opReplaceIndex < replacedOpListForBuffer_.size() &&
295             replacedOpListForBuffer_[opReplaceIndex].first == offset) {
296             auto* replacePtr = opAllocator_.OffsetToAddr(
297                 replacedOpListForBuffer_[opReplaceIndex].second, sizeof(OpItem));
298             if (replacePtr == nullptr) {
299                 LOGE("DrawCmdList::Unmarshalling replace Ops failed, replace op is nullptr");
300                 break;
301             }
302             auto* replaceOpItemPtr = static_cast<OpItem*>(replacePtr);
303             size_t avaliableSize = opAllocator_.GetSize() - replacedOpListForBuffer_[opReplaceIndex].second;
304             auto replaceOp = player.Unmarshalling(replaceOpItemPtr->GetType(), replacePtr, avaliableSize);
305             if (replaceOp) {
306                 drawOpItems_.emplace_back(replaceOp);
307                 replacedOpListForVector_.emplace_back((drawOpItems_.size() - 1), op);
308             } else {
309                 drawOpItems_.emplace_back(op);
310             }
311             opReplaceIndex++;
312         } else {
313             drawOpItems_.emplace_back(op);
314         }
315         if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
316             break;
317         }
318         offset = curOpItemPtr->GetNextOpItemOffset();
319         if (!replacedOpListForBuffer_.empty() && offset >= replacedOpListForBuffer_[0].second) {
320             LOGD("DrawCmdList::UnmarshallingOps seek end by cache textOps");
321             break;
322         }
323     } while (offset != 0 && count <= MAX_OPITEMSIZE);
324     lastOpGenSize_ = opAllocator_.GetSize();
325 
326     if ((int)imageAllocator_.GetSize() > 0) {
327         imageAllocator_.ClearData();
328     }
329 
330     if (performanceCaculateOpType_ != 0) {
331         LOGI("Drawing Performance UnmarshallingDrawOps end %{public}lld", PerformanceCaculate::GetUpTime());
332     }
333 }
334 
Playback(Canvas & canvas,const Rect * rect)335 void DrawCmdList::Playback(Canvas& canvas, const Rect* rect)
336 {
337     if (canvas.GetUICapture() && noNeedUICaptured_) {
338         return;
339     }
340 
341     if (width_ <= 0 || height_ <= 0) {
342         return;
343     }
344     if (performanceCaculateOpType_ != 0) {
345         LOGI("Drawing Performance Playback begin %{public}lld", PerformanceCaculate::GetUpTime());
346     }
347     if (canvas.GetDrawingType() == DrawingType::RECORDING) {
348         PlaybackToDrawCmdList(static_cast<RecordingCanvas&>(canvas).GetDrawCmdList());
349         return;
350     }
351     std::lock_guard<std::recursive_mutex> lock(mutex_);
352 #ifdef ROSEN_OHOS
353     // invalidate cache if high contrast flag changed
354     if (isCached_ && canvas.isHighContrastEnabled() != cachedHighContrast_) {
355         ClearCache();
356     }
357     // Generate or clear cache if cache state changed
358     if (canvas.GetCacheType() == Drawing::CacheType::ENABLED && !isCached_) {
359         GenerateCache(&canvas, rect);
360     } else if (canvas.GetCacheType() == Drawing::CacheType::DISABLED && isCached_) {
361         ClearCache();
362     }
363 #endif
364     Rect tmpRect;
365     if (rect != nullptr) {
366         tmpRect = *rect;
367     }
368     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
369         PlaybackByBuffer(canvas, &tmpRect);
370     } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
371         PlaybackByVector(canvas, &tmpRect);
372     }
373     if (performanceCaculateOpType_ != 0) {
374         DRAWING_PERFORMANCE_STOP_CACULATE;
375         performanceCaculateOpType_ = 0;
376         LOGI("Drawing Performance Playback end %{public}lld", PerformanceCaculate::GetUpTime());
377     }
378 }
379 
GenerateCache(Canvas * canvas,const Rect * rect)380 void DrawCmdList::GenerateCache(Canvas* canvas, const Rect* rect)
381 {
382 #ifdef ROSEN_OHOS
383     if (isCached_) {
384         LOGD("DrawCmdList::GenerateCache Invoke multiple times");
385         return;
386     }
387 
388     std::lock_guard<std::recursive_mutex> lock(mutex_);
389     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
390         GenerateCacheByBuffer(canvas, rect);
391     } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
392         GenerateCacheByVector(canvas, rect);
393     }
394 #endif
395 }
396 
GetIsCache() const397 bool DrawCmdList::GetIsCache() const
398 {
399     return isCached_;
400 }
401 
SetIsCache(bool isCached)402 void DrawCmdList::SetIsCache(bool isCached)
403 {
404     isCached_ = isCached;
405 }
406 
GetCachedHighContrast() const407 bool DrawCmdList::GetCachedHighContrast() const
408 {
409     return cachedHighContrast_;
410 }
411 
SetCachedHighContrast(bool cachedHighContrast)412 void DrawCmdList::SetCachedHighContrast(bool cachedHighContrast)
413 {
414     cachedHighContrast_ = cachedHighContrast;
415 }
416 
GetReplacedOpList()417 std::vector<std::pair<size_t, size_t>> DrawCmdList::GetReplacedOpList()
418 {
419     return replacedOpListForBuffer_;
420 }
421 
SetReplacedOpList(std::vector<std::pair<size_t,size_t>> replacedOpList)422 void DrawCmdList::SetReplacedOpList(std::vector<std::pair<size_t, size_t>> replacedOpList)
423 {
424     replacedOpListForBuffer_ = replacedOpList;
425 }
426 
UpdateNodeIdToPicture(NodeId nodeId)427 void DrawCmdList::UpdateNodeIdToPicture(NodeId nodeId)
428 {
429     if (drawOpItems_.size() == 0) {
430         return;
431     }
432     for (size_t i = 0; i < drawOpItems_.size(); ++i) {
433         auto opItem = drawOpItems_[i];
434         if (!opItem) {
435             continue;
436         }
437         opItem->SetNodeId(nodeId);
438     }
439 }
440 
ClearCache()441 void DrawCmdList::ClearCache()
442 {
443 #ifdef ROSEN_OHOS
444     // restore the original op
445     for (auto& [index, op] : replacedOpListForVector_) {
446         op.swap(drawOpItems_[index]);
447     }
448     replacedOpListForVector_.clear();
449     replacedOpListForBuffer_.clear();
450     isCached_ = false;
451 #endif
452 }
453 
GenerateCacheByVector(Canvas * canvas,const Rect * rect)454 void DrawCmdList::GenerateCacheByVector(Canvas* canvas, const Rect* rect)
455 {
456 #ifdef ROSEN_OHOS
457     if (drawOpItems_.size() == 0) {
458         return;
459     }
460     uint32_t opSize = drawOpItems_.size();
461     for (auto index = 0u; index < opSize; ++index) {
462         std::shared_ptr<DrawOpItem> op = drawOpItems_[index];
463         if (!op || op->GetType() != DrawOpItem::TEXT_BLOB_OPITEM) {
464             continue;
465         }
466         DrawTextBlobOpItem* textBlobOp = static_cast<DrawTextBlobOpItem*>(op.get());
467         auto replaceCache = textBlobOp->GenerateCachedOpItem(canvas);
468         if (replaceCache) {
469             replacedOpListForVector_.emplace_back(index, op);
470             drawOpItems_[index] = replaceCache;
471         }
472     }
473     isCached_ = true;
474     cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
475 #endif
476 }
477 
GenerateCacheByBuffer(Canvas * canvas,const Rect * rect)478 void DrawCmdList::GenerateCacheByBuffer(Canvas* canvas, const Rect* rect)
479 {
480 #ifdef ROSEN_OHOS
481     if (opAllocator_.GetSize() <= offset_) {
482         return;
483     }
484 
485     size_t offset = offset_;
486     GenerateCachedOpItemPlayer player = { *this, canvas, rect };
487     uint32_t maxOffset = opAllocator_.GetSize();
488     uint32_t count = 0;
489     do {
490         count++;
491         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
492         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
493         if (curOpItemPtr == nullptr) {
494             LOGE("DrawCmdList::GenerateCacheByBuffer failed, opItem is nullptr");
495             break;
496         }
497         size_t avaliableSize = opAllocator_.GetSize() - offset;
498         bool replaceSuccess = player.GenerateCachedOpItem(curOpItemPtr->GetType(), itemPtr, avaliableSize);
499         if (replaceSuccess) {
500             replacedOpListForBuffer_.push_back({offset, lastOpItemOffset_.value()});
501             itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
502             curOpItemPtr = static_cast<OpItem*>(itemPtr);
503             if (curOpItemPtr == nullptr) {
504                 LOGE("DrawCmdList::GenerateCache failed, opItem is nullptr");
505                 break;
506             }
507         }
508         if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
509             break;
510         }
511         offset = curOpItemPtr->GetNextOpItemOffset();
512     } while (offset != 0 && offset < maxOffset && count <= MAX_OPITEMSIZE);
513     isCached_ = true;
514     cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
515 #endif
516 }
517 
PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)518 void DrawCmdList::PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)
519 {
520     if (!drawCmdList) {
521         return;
522     }
523     std::lock_guard<std::recursive_mutex> lock(mutex_);
524     if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
525         std::lock_guard<std::recursive_mutex> lock(drawCmdList->mutex_);
526         drawCmdList->drawOpItems_.insert(drawCmdList->drawOpItems_.end(), drawOpItems_.begin(), drawOpItems_.end());
527         return;
528     }
529 
530     void* addr = opAllocator_.OffsetToAddr(offset_, 0);
531     if (addr == nullptr) {
532         return;
533     }
534 
535     {
536         std::lock_guard<std::mutex> lock(drawCmdList->recordCmdMutex_);
537         drawCmdList->recordCmdVec_.swap(recordCmdVec_);
538     }
539 #ifdef SUPPORT_OHOS_PIXMAP
540     {
541         std::lock_guard<std::mutex> lock(drawCmdList->imageObjectMutex_);
542         drawCmdList->imageObjectVec_.swap(imageObjectVec_);
543     }
544 #endif
545     {
546         std::lock_guard<std::mutex> lock(drawCmdList->imageBaseObjMutex_);
547         drawCmdList->imageBaseObjVec_.swap(imageBaseObjVec_);
548     }
549     size_t size = opAllocator_.GetSize() - offset_;
550     auto imageData = GetAllImageData();
551     auto bitmapData = GetAllBitmapData();
552     drawCmdList->opAllocator_.Add(addr, size);
553     if (imageData.first != nullptr && imageData.second != 0) {
554         drawCmdList->AddImageData(imageData.first, imageData.second);
555     }
556 
557     if (bitmapData.first != nullptr && bitmapData.second != 0) {
558         drawCmdList->AddBitmapData(bitmapData.first, bitmapData.second);
559     }
560 }
561 
PlaybackByVector(Canvas & canvas,const Rect * rect)562 void DrawCmdList::PlaybackByVector(Canvas& canvas, const Rect* rect)
563 {
564     if (drawOpItems_.empty()) {
565         return;
566     }
567     uint32_t opCount = 0;
568     for (auto op : drawOpItems_) {
569         if (isCanvasDrawingOpLimitEnabled_ && opCount > DRAWCMDLIST_OPSIZE_COUNT_LIMIT) {
570             LOGE("DrawCmdList::PlaybackByVector Out of DrawOp limit, DrawOpCount: %{public}d", opCount);
571             break;
572         }
573         if (op) {
574             op->Playback(&canvas, rect);
575             ++opCount;
576         }
577     }
578     canvas.DetachPaint();
579 }
580 
PlaybackByBuffer(Canvas & canvas,const Rect * rect)581 void DrawCmdList::PlaybackByBuffer(Canvas& canvas, const Rect* rect)
582 {
583     if (opAllocator_.GetSize() <= offset_) {
584         return;
585     }
586     size_t offset = offset_;
587     if (lastOpGenSize_ != opAllocator_.GetSize()) {
588         uint32_t count = 0;
589         UnmarshallingPlayer player = { *this };
590         drawOpItems_.clear();
591         do {
592             count++;
593             void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
594             auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
595             if (curOpItemPtr == nullptr) {
596                 break;
597             }
598             uint32_t type = curOpItemPtr->GetType();
599             if (auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset)) {
600                 drawOpItems_.emplace_back(op);
601             }
602             if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
603                 break;
604             }
605             offset = curOpItemPtr->GetNextOpItemOffset();
606         } while (offset != 0 && count <= MAX_OPITEMSIZE);
607         lastOpGenSize_ = opAllocator_.GetSize();
608     }
609     uint32_t opCount = 0;
610     for (auto op : drawOpItems_) {
611         if (isCanvasDrawingOpLimitEnabled_ && opCount > DRAWCMDLIST_OPSIZE_COUNT_LIMIT) {
612             LOGE("DrawCmdList::PlaybackByBuffer Out of DrawOp limit, DrawOpCount: %{public}d", opCount);
613             break;
614         }
615         if (op) {
616             op->Playback(&canvas, rect);
617             ++opCount;
618         }
619     }
620     canvas.DetachPaint();
621 }
622 
CountTextBlobNum()623 size_t DrawCmdList::CountTextBlobNum()
624 {
625     size_t textBlobCnt = 0;
626     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
627         size_t offset = offset_;
628         size_t maxOffset = opAllocator_.GetSize();
629         uint32_t count = 0;
630         do {
631             count++;
632             void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
633             auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
634             if (curOpItemPtr == nullptr) {
635                 break;
636             }
637             uint32_t type = curOpItemPtr->GetType();
638             if (type == DrawOpItem::TEXT_BLOB_OPITEM) {
639                 textBlobCnt++;
640             }
641             if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
642                 break;
643             }
644             offset = curOpItemPtr->GetNextOpItemOffset();
645         } while (offset != 0 && offset < maxOffset && count <= MAX_OPITEMSIZE);
646     }
647     return textBlobCnt;
648 }
649 
PatchTypefaceIds()650 void DrawCmdList::PatchTypefaceIds()
651 {
652     constexpr int bitNumber = 30 + 32;
653     uint64_t replayMask = (uint64_t)1 << bitNumber;
654     size_t offset = offset_;
655     size_t maxOffset = opAllocator_.GetSize();
656     uint32_t count = 0;
657     do {
658         count++;
659         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
660         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
661         if (curOpItemPtr == nullptr) {
662             break;
663         }
664         uint32_t type = curOpItemPtr->GetType();
665         if (type == DrawOpItem::TEXT_BLOB_OPITEM) {
666             DrawTextBlobOpItem::ConstructorHandle* handle =
667                 static_cast<DrawTextBlobOpItem::ConstructorHandle*>(curOpItemPtr);
668             if (handle->globalUniqueId) {
669                 handle->globalUniqueId |= replayMask;
670             }
671         }
672         if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
673             break;
674         }
675         offset = curOpItemPtr->GetNextOpItemOffset();
676     } while (offset != 0 && offset < maxOffset && count <= MAX_OPITEMSIZE);
677 }
678 
Purge()679 void DrawCmdList::Purge()
680 {
681     std::lock_guard<std::recursive_mutex> lock(mutex_);
682     for (auto op : drawOpItems_) {
683         if (!op) {
684             continue;
685         }
686         auto type = op->GetType();
687         if (type == DrawOpItem::PIXELMAP_RECT_OPITEM ||
688             type == DrawOpItem::PIXELMAP_WITH_PARM_OPITEM ||
689             type == DrawOpItem::PIXELMAP_NINE_OPITEM ||
690             type == DrawOpItem::PIXELMAP_LATTICE_OPITEM) {
691             op->Purge();
692         }
693     }
694 }
695 
SetIsNeedUnmarshalOnDestruct(bool isNeedUnmarshalOnDestruct)696 void DrawCmdList::SetIsNeedUnmarshalOnDestruct(bool isNeedUnmarshalOnDestruct)
697 {
698     isNeedUnmarshalOnDestruct_ = isNeedUnmarshalOnDestruct;
699 }
700 
GetSize()701 size_t DrawCmdList::GetSize()
702 {
703     size_t totoalSize = sizeof(*this);
704 
705     {
706         std::lock_guard<std::recursive_mutex> lock(mutex_);
707         totoalSize += opAllocator_.GetSize() + imageAllocator_.GetSize() + bitmapAllocator_.GetSize();
708         for (auto op : drawOpItems_) {
709             if (op) {
710                 totoalSize += op->GetOpSize();
711             }
712         }
713     }
714     return totoalSize;
715 }
716 
SetCanvasDrawingOpLimitEnable(bool isEnable)717 void DrawCmdList::SetCanvasDrawingOpLimitEnable(bool isEnable)
718 {
719     isCanvasDrawingOpLimitEnabled_ = isEnable;
720 }
721 } // namespace Drawing
722 } // namespace Rosen
723 } // namespace OHOS
724