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 
CreateFromData(const CmdListData & data,bool isCopy)30 std::shared_ptr<DrawCmdList> DrawCmdList::CreateFromData(const CmdListData& data, bool isCopy)
31 {
32     auto cmdList = std::make_shared<DrawCmdList>(DrawCmdList::UnmarshalMode::DEFERRED);
33     if (isCopy) {
34         cmdList->opAllocator_.BuildFromDataWithCopy(data.first, data.second);
35     } else {
36         cmdList->opAllocator_.BuildFromData(data.first, data.second);
37     }
38 
39     int32_t* width = static_cast<int32_t*>(cmdList->opAllocator_.OffsetToAddr(0, sizeof(int32_t)));
40     int32_t* height = static_cast<int32_t*>(cmdList->opAllocator_.OffsetToAddr(sizeof(int32_t), sizeof(int32_t)));
41     if (width && height) {
42         cmdList->width_ = *width;
43         cmdList->height_ = *height;
44     } else {
45         cmdList->width_ = 0;
46         cmdList->height_ = 0;
47     }
48     return cmdList;
49 }
50 
DrawCmdList(DrawCmdList::UnmarshalMode mode)51 DrawCmdList::DrawCmdList(DrawCmdList::UnmarshalMode mode) : width_(0), height_(0), mode_(mode) {}
52 
DrawCmdList(int32_t width,int32_t height,DrawCmdList::UnmarshalMode mode)53 DrawCmdList::DrawCmdList(int32_t width, int32_t height, DrawCmdList::UnmarshalMode mode)
54     : width_(width), height_(height), mode_(mode)
55 {
56     opAllocator_.Add(&width_, sizeof(int32_t));
57     opAllocator_.Add(&height_, sizeof(int32_t));
58 }
59 
~DrawCmdList()60 DrawCmdList::~DrawCmdList()
61 {
62     if (drawOpItems_.size() == 0 && isNeedUnmarshalOnDestruct_) {
63         UnmarshallingDrawOps();
64     }
65     ClearOp();
66 }
67 
AddDrawOp(std::shared_ptr<DrawOpItem> && drawOpItem)68 bool DrawCmdList::AddDrawOp(std::shared_ptr<DrawOpItem>&& drawOpItem)
69 {
70     if (mode_ != DrawCmdList::UnmarshalMode::DEFERRED) {
71         return false;
72     }
73     std::lock_guard<std::recursive_mutex> lock(mutex_);
74     drawOpItems_.emplace_back(drawOpItem);
75     return true;
76 }
77 
ClearOp()78 void DrawCmdList::ClearOp()
79 {
80     {
81         std::lock_guard<std::recursive_mutex> lock(mutex_);
82         opAllocator_.ClearData();
83         opAllocator_.Add(&width_, sizeof(int32_t));
84         opAllocator_.Add(&height_, sizeof(int32_t));
85         imageAllocator_.ClearData();
86         bitmapAllocator_.ClearData();
87         imageMap_.clear();
88         imageHandleVec_.clear();
89         drawOpItems_.clear();
90         lastOpGenSize_ = 0;
91         lastOpItemOffset_ = std::nullopt;
92         opCnt_ = 0;
93     }
94     {
95         std::lock_guard<std::mutex> lock(recordCmdMutex_);
96         recordCmdVec_.clear();
97     }
98     {
99         std::lock_guard<std::mutex> lock(imageObjectMutex_);
100         imageObjectVec_.clear();
101     }
102     {
103         std::lock_guard<std::mutex> lock(imageBaseObjMutex_);
104         imageBaseObjVec_.clear();
105     }
106 }
107 
GetWidth() const108 int32_t DrawCmdList::GetWidth() const
109 {
110     return width_;
111 }
112 
GetHeight() const113 int32_t DrawCmdList::GetHeight() const
114 {
115     return height_;
116 }
117 
SetWidth(int32_t width)118 void DrawCmdList::SetWidth(int32_t width)
119 {
120     width_ = width;
121 }
122 
SetHeight(int32_t height)123 void DrawCmdList::SetHeight(int32_t height)
124 {
125     height_ = height;
126 }
127 
IsEmpty() const128 bool DrawCmdList::IsEmpty() const
129 {
130     if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
131         return drawOpItems_.empty();
132     }
133     size_t offset = 2 * sizeof(int32_t); // 2 is width and height.Offset of first OpItem is behind the w and h
134     if (opAllocator_.GetSize() <= offset && drawOpItems_.size() == 0) {
135         return true;
136     }
137     return false;
138 }
139 
GetOpItemSize() const140 size_t DrawCmdList::GetOpItemSize() const
141 {
142     return mode_ == DrawCmdList::UnmarshalMode::DEFERRED ? drawOpItems_.size() : opCnt_;
143 }
144 
GetOpsWithDesc() const145 std::string DrawCmdList::GetOpsWithDesc() const
146 {
147     std::string desc;
148     for (auto& item : drawOpItems_) {
149         if (item == nullptr) {
150             continue;
151         }
152         desc += item->GetOpDesc();
153         desc += "\n";
154     }
155     LOGD("DrawCmdList::GetOpsWithDesc %{public}s, opitem sz: %{public}zu", desc.c_str(), drawOpItems_.size());
156     return desc;
157 }
158 
Dump(std::string & out)159 void DrawCmdList::Dump(std::string& out)
160 {
161     std::lock_guard<std::recursive_mutex> lock(mutex_);
162     for (auto& item : drawOpItems_) {
163         if (item == nullptr) {
164             continue;
165         }
166         item->Dump(out);
167         out += " ";
168     }
169     if (drawOpItems_.size() > 0) {
170         out.pop_back();
171     }
172 }
173 
MarshallingDrawOps()174 void DrawCmdList::MarshallingDrawOps()
175 {
176     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
177         return;
178     }
179     std::lock_guard<std::recursive_mutex> lock(mutex_);
180     if (replacedOpListForVector_.empty()) {
181         for (auto& op : drawOpItems_) {
182             if (op) {
183                 op->Marshalling(*this);
184             }
185         }
186         return;
187     }
188     for (auto& [index, op] : replacedOpListForVector_) {
189         op.swap(drawOpItems_[index]);
190     }
191     std::vector<uint32_t> opIndexForCache(replacedOpListForVector_.size());
192     uint32_t opReplaceIndex = 0;
193     for (auto index = 0u; index < drawOpItems_.size(); ++index) {
194         if (drawOpItems_[index]) {
195             drawOpItems_[index]->Marshalling(*this);
196         }
197         if (index == static_cast<size_t>(replacedOpListForVector_[opReplaceIndex].first)) {
198             opIndexForCache[opReplaceIndex] = lastOpItemOffset_.value();
199             ++opReplaceIndex;
200         }
201     }
202     for (auto index = 0u; index < replacedOpListForVector_.size(); ++index) {
203         if (replacedOpListForVector_[index].second) {
204             replacedOpListForVector_[index].second->Marshalling(*this);
205         }
206         replacedOpListForBuffer_.emplace_back(opIndexForCache[index], lastOpItemOffset_.value());
207     }
208 }
209 
CaculatePerformanceOpType()210 void DrawCmdList::CaculatePerformanceOpType()
211 {
212     size_t offset = offset_;
213     const int caculatePerformaceCount = 500;    // 被测单接口用例至少出现500次以上
214     std::map<uint32_t, uint32_t> opTypeCountMap;
215     uint32_t count = 0;
216     do {
217         count++;
218         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
219         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
220         if (curOpItemPtr == nullptr) {
221             break;
222         }
223         uint32_t type = curOpItemPtr->GetType();
224         if (opTypeCountMap.find(type) != opTypeCountMap.end()) {
225             if (++opTypeCountMap[type] > caculatePerformaceCount) {
226                 performanceCaculateOpType_ = type;
227                 DRAWING_PERFORMANCE_START_CACULATE;
228                 return;
229             }
230         } else {
231             opTypeCountMap[type] = 1;   // 记录出现的第1次
232         }
233         if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
234             break;
235         }
236         offset = curOpItemPtr->GetNextOpItemOffset();
237     } while (offset != 0 && count <= MAX_OPITEMSIZE);
238 }
239 
UnmarshallingDrawOps(uint32_t * opItemCount)240 void DrawCmdList::UnmarshallingDrawOps(uint32_t* opItemCount)
241 {
242     if (PerformanceCaculate::GetDrawingTestRecordingEnabled()) {
243         CaculatePerformanceOpType();
244     }
245     if (performanceCaculateOpType_ != 0) {
246         LOGI("Drawing Performance UnmarshallingDrawOps begin %{public}lld", PerformanceCaculate::GetUpTime());
247     }
248 
249     if (opAllocator_.GetSize() <= offset_ || width_ <= 0 || height_ <= 0) {
250         return;
251     }
252 
253     UnmarshallingPlayer player = { *this };
254     drawOpItems_.clear();
255     lastOpGenSize_ = 0;
256     uint32_t opReplaceIndex = 0;
257     size_t offset = offset_;
258     uint32_t count = 0;
259     do {
260         count++;
261         if (opItemCount && ++(*opItemCount) > MAX_OPITEMSIZE) {
262             break;
263         }
264         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
265         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
266         if (curOpItemPtr == nullptr) {
267             LOGE("DrawCmdList::UnmarshallingOps failed, opItem is nullptr");
268             break;
269         }
270         uint32_t type = curOpItemPtr->GetType();
271         auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset);
272         if (!op) {
273             if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
274                 break;
275             }
276             offset = curOpItemPtr->GetNextOpItemOffset();
277             continue;
278         }
279         if (opReplaceIndex < replacedOpListForBuffer_.size() &&
280             replacedOpListForBuffer_[opReplaceIndex].first == offset) {
281             auto* replacePtr = opAllocator_.OffsetToAddr(
282                 replacedOpListForBuffer_[opReplaceIndex].second, sizeof(OpItem));
283             if (replacePtr == nullptr) {
284                 LOGE("DrawCmdList::Unmarshalling replace Ops failed, replace op is nullptr");
285                 break;
286             }
287             auto* replaceOpItemPtr = static_cast<OpItem*>(replacePtr);
288             size_t avaliableSize = opAllocator_.GetSize() - replacedOpListForBuffer_[opReplaceIndex].second;
289             auto replaceOp = player.Unmarshalling(replaceOpItemPtr->GetType(), replacePtr, avaliableSize);
290             if (replaceOp) {
291                 drawOpItems_.emplace_back(replaceOp);
292                 replacedOpListForVector_.emplace_back((drawOpItems_.size() - 1), op);
293             } else {
294                 drawOpItems_.emplace_back(op);
295             }
296             opReplaceIndex++;
297         } else {
298             drawOpItems_.emplace_back(op);
299         }
300         if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
301             break;
302         }
303         offset = curOpItemPtr->GetNextOpItemOffset();
304         if (!replacedOpListForBuffer_.empty() && offset >= replacedOpListForBuffer_[0].second) {
305             LOGD("DrawCmdList::UnmarshallingOps seek end by cache textOps");
306             break;
307         }
308     } while (offset != 0 && count <= MAX_OPITEMSIZE);
309     lastOpGenSize_ = opAllocator_.GetSize();
310 
311     if ((int)imageAllocator_.GetSize() > 0) {
312         imageAllocator_.ClearData();
313     }
314 
315     if (performanceCaculateOpType_ != 0) {
316         LOGI("Drawing Performance UnmarshallingDrawOps end %{public}lld", PerformanceCaculate::GetUpTime());
317     }
318 }
319 
Playback(Canvas & canvas,const Rect * rect)320 void DrawCmdList::Playback(Canvas& canvas, const Rect* rect)
321 {
322     if (width_ <= 0 || height_ <= 0) {
323         return;
324     }
325     if (performanceCaculateOpType_ != 0) {
326         LOGI("Drawing Performance Playback begin %{public}lld", PerformanceCaculate::GetUpTime());
327     }
328     if (canvas.GetDrawingType() == DrawingType::RECORDING) {
329         PlaybackToDrawCmdList(static_cast<RecordingCanvas&>(canvas).GetDrawCmdList());
330         return;
331     }
332     std::lock_guard<std::recursive_mutex> lock(mutex_);
333 #ifdef ROSEN_OHOS
334     // invalidate cache if high contrast flag changed
335     if (isCached_ && canvas.isHighContrastEnabled() != cachedHighContrast_) {
336         ClearCache();
337     }
338     // Generate or clear cache if cache state changed
339     if (canvas.GetCacheType() == Drawing::CacheType::ENABLED && !isCached_) {
340         GenerateCache(&canvas, rect);
341     } else if (canvas.GetCacheType() == Drawing::CacheType::DISABLED && isCached_) {
342         ClearCache();
343     }
344 #endif
345     Rect tmpRect;
346     if (rect != nullptr) {
347         tmpRect = *rect;
348     }
349     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
350         PlaybackByBuffer(canvas, &tmpRect);
351     } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
352         PlaybackByVector(canvas, &tmpRect);
353     }
354     if (performanceCaculateOpType_ != 0) {
355         DRAWING_PERFORMANCE_STOP_CACULATE;
356         performanceCaculateOpType_ = 0;
357         LOGI("Drawing Performance Playback end %{public}lld", PerformanceCaculate::GetUpTime());
358     }
359 }
360 
GenerateCache(Canvas * canvas,const Rect * rect)361 void DrawCmdList::GenerateCache(Canvas* canvas, const Rect* rect)
362 {
363 #ifdef ROSEN_OHOS
364     if (isCached_) {
365         LOGD("DrawCmdList::GenerateCache Invoke multiple times");
366         return;
367     }
368 
369     std::lock_guard<std::recursive_mutex> lock(mutex_);
370     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
371         GenerateCacheByBuffer(canvas, rect);
372     } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
373         GenerateCacheByVector(canvas, rect);
374     }
375 #endif
376 }
377 
GetIsCache() const378 bool DrawCmdList::GetIsCache() const
379 {
380     return isCached_;
381 }
382 
SetIsCache(bool isCached)383 void DrawCmdList::SetIsCache(bool isCached)
384 {
385     isCached_ = isCached;
386 }
387 
GetCachedHighContrast() const388 bool DrawCmdList::GetCachedHighContrast() const
389 {
390     return cachedHighContrast_;
391 }
392 
SetCachedHighContrast(bool cachedHighContrast)393 void DrawCmdList::SetCachedHighContrast(bool cachedHighContrast)
394 {
395     cachedHighContrast_ = cachedHighContrast;
396 }
397 
GetReplacedOpList()398 std::vector<std::pair<size_t, size_t>> DrawCmdList::GetReplacedOpList()
399 {
400     return replacedOpListForBuffer_;
401 }
402 
SetReplacedOpList(std::vector<std::pair<size_t,size_t>> replacedOpList)403 void DrawCmdList::SetReplacedOpList(std::vector<std::pair<size_t, size_t>> replacedOpList)
404 {
405     replacedOpListForBuffer_ = replacedOpList;
406 }
407 
UpdateNodeIdToPicture(NodeId nodeId)408 void DrawCmdList::UpdateNodeIdToPicture(NodeId nodeId)
409 {
410     if (drawOpItems_.size() == 0) {
411         return;
412     }
413     for (size_t i = 0; i < drawOpItems_.size(); ++i) {
414         auto opItem = drawOpItems_[i];
415         if (!opItem) {
416             continue;
417         }
418         opItem->SetNodeId(nodeId);
419     }
420 }
421 
ClearCache()422 void DrawCmdList::ClearCache()
423 {
424 #ifdef ROSEN_OHOS
425     // restore the original op
426     for (auto& [index, op] : replacedOpListForVector_) {
427         op.swap(drawOpItems_[index]);
428     }
429     replacedOpListForVector_.clear();
430     replacedOpListForBuffer_.clear();
431     isCached_ = false;
432 #endif
433 }
434 
GenerateCacheByVector(Canvas * canvas,const Rect * rect)435 void DrawCmdList::GenerateCacheByVector(Canvas* canvas, const Rect* rect)
436 {
437 #ifdef ROSEN_OHOS
438     if (drawOpItems_.size() == 0) {
439         return;
440     }
441     uint32_t opSize = drawOpItems_.size();
442     for (auto index = 0u; index < opSize; ++index) {
443         std::shared_ptr<DrawOpItem> op = drawOpItems_[index];
444         if (!op || op->GetType() != DrawOpItem::TEXT_BLOB_OPITEM) {
445             continue;
446         }
447         DrawTextBlobOpItem* textBlobOp = static_cast<DrawTextBlobOpItem*>(op.get());
448         auto replaceCache = textBlobOp->GenerateCachedOpItem(canvas);
449         if (replaceCache) {
450             replacedOpListForVector_.emplace_back(index, op);
451             drawOpItems_[index] = replaceCache;
452         }
453     }
454     isCached_ = true;
455     cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
456 #endif
457 }
458 
GenerateCacheByBuffer(Canvas * canvas,const Rect * rect)459 void DrawCmdList::GenerateCacheByBuffer(Canvas* canvas, const Rect* rect)
460 {
461 #ifdef ROSEN_OHOS
462     if (opAllocator_.GetSize() <= offset_) {
463         return;
464     }
465 
466     size_t offset = offset_;
467     GenerateCachedOpItemPlayer player = { *this, canvas, rect };
468     uint32_t maxOffset = opAllocator_.GetSize();
469     uint32_t count = 0;
470     do {
471         count++;
472         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
473         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
474         if (curOpItemPtr == nullptr) {
475             LOGE("DrawCmdList::GenerateCacheByBuffer failed, opItem is nullptr");
476             break;
477         }
478         size_t avaliableSize = opAllocator_.GetSize() - offset;
479         bool replaceSuccess = player.GenerateCachedOpItem(curOpItemPtr->GetType(), itemPtr, avaliableSize);
480         if (replaceSuccess) {
481             replacedOpListForBuffer_.push_back({offset, lastOpItemOffset_.value()});
482             itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
483             curOpItemPtr = static_cast<OpItem*>(itemPtr);
484             if (curOpItemPtr == nullptr) {
485                 LOGE("DrawCmdList::GenerateCache failed, opItem is nullptr");
486                 break;
487             }
488         }
489         if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
490             break;
491         }
492         offset = curOpItemPtr->GetNextOpItemOffset();
493     } while (offset != 0 && offset < maxOffset && count <= MAX_OPITEMSIZE);
494     isCached_ = true;
495     cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
496 #endif
497 }
498 
PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)499 void DrawCmdList::PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)
500 {
501     if (!drawCmdList) {
502         return;
503     }
504     std::lock_guard<std::recursive_mutex> lock(mutex_);
505     if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
506         std::lock_guard<std::recursive_mutex> lock(drawCmdList->mutex_);
507         drawCmdList->drawOpItems_.insert(drawCmdList->drawOpItems_.end(), drawOpItems_.begin(), drawOpItems_.end());
508         return;
509     }
510 
511     void* addr = opAllocator_.OffsetToAddr(offset_, 0);
512     if (addr == nullptr) {
513         return;
514     }
515 
516     {
517         std::lock_guard<std::mutex> lock(drawCmdList->recordCmdMutex_);
518         drawCmdList->recordCmdVec_.swap(recordCmdVec_);
519     }
520 #ifdef SUPPORT_OHOS_PIXMAP
521     {
522         std::lock_guard<std::mutex> lock(drawCmdList->imageObjectMutex_);
523         drawCmdList->imageObjectVec_.swap(imageObjectVec_);
524     }
525 #endif
526     {
527         std::lock_guard<std::mutex> lock(drawCmdList->imageBaseObjMutex_);
528         drawCmdList->imageBaseObjVec_.swap(imageBaseObjVec_);
529     }
530     size_t size = opAllocator_.GetSize() - offset_;
531     auto imageData = GetAllImageData();
532     auto bitmapData = GetAllBitmapData();
533     drawCmdList->opAllocator_.Add(addr, size);
534     if (imageData.first != nullptr && imageData.second != 0) {
535         drawCmdList->AddImageData(imageData.first, imageData.second);
536     }
537 
538     if (bitmapData.first != nullptr && bitmapData.second != 0) {
539         drawCmdList->AddBitmapData(bitmapData.first, bitmapData.second);
540     }
541 }
542 
PlaybackByVector(Canvas & canvas,const Rect * rect)543 void DrawCmdList::PlaybackByVector(Canvas& canvas, const Rect* rect)
544 {
545     if (drawOpItems_.empty()) {
546         return;
547     }
548     for (auto op : drawOpItems_) {
549         if (op) {
550             op->Playback(&canvas, rect);
551         }
552     }
553     canvas.DetachPaint();
554 }
555 
PlaybackByBuffer(Canvas & canvas,const Rect * rect)556 void DrawCmdList::PlaybackByBuffer(Canvas& canvas, const Rect* rect)
557 {
558     if (opAllocator_.GetSize() <= offset_) {
559         return;
560     }
561     size_t offset = offset_;
562     if (lastOpGenSize_ != opAllocator_.GetSize()) {
563         uint32_t count = 0;
564         UnmarshallingPlayer player = { *this };
565         drawOpItems_.clear();
566         do {
567             count++;
568             void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
569             auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
570             if (curOpItemPtr == nullptr) {
571                 break;
572             }
573             uint32_t type = curOpItemPtr->GetType();
574             if (auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset)) {
575                 drawOpItems_.emplace_back(op);
576             }
577             if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
578                 break;
579             }
580             offset = curOpItemPtr->GetNextOpItemOffset();
581         } while (offset != 0 && count <= MAX_OPITEMSIZE);
582         lastOpGenSize_ = opAllocator_.GetSize();
583     }
584     for (auto op : drawOpItems_) {
585         if (op) {
586             op->Playback(&canvas, rect);
587         }
588     }
589     canvas.DetachPaint();
590 }
591 
CountTextBlobNum()592 size_t DrawCmdList::CountTextBlobNum()
593 {
594     size_t textBlobCnt = 0;
595     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
596         size_t offset = offset_;
597         size_t maxOffset = opAllocator_.GetSize();
598         uint32_t count = 0;
599         do {
600             count++;
601             void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
602             auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
603             if (curOpItemPtr == nullptr) {
604                 break;
605             }
606             uint32_t type = curOpItemPtr->GetType();
607             if (type == DrawOpItem::TEXT_BLOB_OPITEM) {
608                 textBlobCnt++;
609             }
610             if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
611                 break;
612             }
613             offset = curOpItemPtr->GetNextOpItemOffset();
614         } while (offset != 0 && offset < maxOffset && count <= MAX_OPITEMSIZE);
615     }
616     return textBlobCnt;
617 }
618 
Purge()619 void DrawCmdList::Purge()
620 {
621     std::lock_guard<std::recursive_mutex> lock(mutex_);
622     for (auto op : drawOpItems_) {
623         if (!op) {
624             continue;
625         }
626         auto type = op->GetType();
627         if (type == DrawOpItem::PIXELMAP_RECT_OPITEM ||
628             type == DrawOpItem::PIXELMAP_WITH_PARM_OPITEM) {
629             op->Purge();
630         }
631     }
632 }
633 
SetIsNeedUnmarshalOnDestruct(bool isNeedUnmarshalOnDestruct)634 void DrawCmdList::SetIsNeedUnmarshalOnDestruct(bool isNeedUnmarshalOnDestruct)
635 {
636     isNeedUnmarshalOnDestruct_ = isNeedUnmarshalOnDestruct;
637 }
638 } // namespace Drawing
639 } // namespace Rosen
640 } // namespace OHOS
641