• 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 
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) {
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     do {
216         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
217         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
218         if (curOpItemPtr == nullptr) {
219             break;
220         }
221         uint32_t type = curOpItemPtr->GetType();
222         if (opTypeCountMap.find(type) != opTypeCountMap.end()) {
223             if (++opTypeCountMap[type] > caculatePerformaceCount) {
224                 performanceCaculateOpType_ = type;
225                 DRAWING_PERFORMANCE_START_CACULATE;
226                 return;
227             }
228         } else {
229             opTypeCountMap[type] = 1;   // 记录出现的第1次
230         }
231         offset = curOpItemPtr->GetNextOpItemOffset();
232     } while (offset != 0);
233 }
234 
UnmarshallingDrawOps()235 void DrawCmdList::UnmarshallingDrawOps()
236 {
237     if (PerformanceCaculate::GetDrawingTestRecordingEnabled()) {
238         CaculatePerformanceOpType();
239     }
240     if (performanceCaculateOpType_ != 0) {
241         LOGI("Drawing Performance UnmarshallingDrawOps begin %{public}lld", PerformanceCaculate::GetUpTime());
242     }
243 
244     if (opAllocator_.GetSize() <= offset_ || width_ <= 0 || height_ <= 0) {
245         return;
246     }
247 
248     UnmarshallingPlayer player = { *this };
249     drawOpItems_.clear();
250     lastOpGenSize_ = 0;
251     uint32_t opReplaceIndex = 0;
252     size_t offset = offset_;
253     do {
254         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
255         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
256         if (curOpItemPtr == nullptr) {
257             LOGE("DrawCmdList::UnmarshallingOps failed, opItem is nullptr");
258             break;
259         }
260         uint32_t type = curOpItemPtr->GetType();
261         auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset);
262         if (!op) {
263             offset = curOpItemPtr->GetNextOpItemOffset();
264             continue;
265         }
266         if (opReplaceIndex < replacedOpListForBuffer_.size() &&
267             replacedOpListForBuffer_[opReplaceIndex].first == offset) {
268             auto* replacePtr = opAllocator_.OffsetToAddr(
269                 replacedOpListForBuffer_[opReplaceIndex].second, sizeof(OpItem));
270             if (replacePtr == nullptr) {
271                 LOGE("DrawCmdList::Unmarshalling replace Ops failed, replace op is nullptr");
272                 break;
273             }
274             auto* replaceOpItemPtr = static_cast<OpItem*>(replacePtr);
275             size_t avaliableSize = opAllocator_.GetSize() - replacedOpListForBuffer_[opReplaceIndex].second;
276             auto replaceOp = player.Unmarshalling(replaceOpItemPtr->GetType(), replacePtr, avaliableSize);
277             if (replaceOp) {
278                 drawOpItems_.emplace_back(replaceOp);
279                 replacedOpListForVector_.emplace_back((drawOpItems_.size() - 1), op);
280             } else {
281                 drawOpItems_.emplace_back(op);
282             }
283             opReplaceIndex++;
284         } else {
285             drawOpItems_.emplace_back(op);
286         }
287         offset = curOpItemPtr->GetNextOpItemOffset();
288         if (!replacedOpListForBuffer_.empty() && offset >= replacedOpListForBuffer_[0].second) {
289             LOGD("DrawCmdList::UnmarshallingOps seek end by cache textOps");
290             break;
291         }
292     } while (offset != 0);
293     lastOpGenSize_ = opAllocator_.GetSize();
294 
295     if ((int)imageAllocator_.GetSize() > 0) {
296         imageAllocator_.ClearData();
297     }
298 
299     if (performanceCaculateOpType_ != 0) {
300         LOGI("Drawing Performance UnmarshallingDrawOps end %{public}lld", PerformanceCaculate::GetUpTime());
301     }
302 }
303 
Playback(Canvas & canvas,const Rect * rect)304 void DrawCmdList::Playback(Canvas& canvas, const Rect* rect)
305 {
306     if (width_ <= 0 || height_ <= 0) {
307         return;
308     }
309     if (performanceCaculateOpType_ != 0) {
310         LOGI("Drawing Performance Playback begin %{public}lld", PerformanceCaculate::GetUpTime());
311     }
312     if (canvas.GetDrawingType() == DrawingType::RECORDING) {
313         PlaybackToDrawCmdList(static_cast<RecordingCanvas&>(canvas).GetDrawCmdList());
314         return;
315     }
316     std::lock_guard<std::recursive_mutex> lock(mutex_);
317 #ifdef ROSEN_OHOS
318     // invalidate cache if high contrast flag changed
319     if (isCached_ && canvas.isHighContrastEnabled() != cachedHighContrast_) {
320         ClearCache();
321     }
322     // Generate or clear cache if cache state changed
323     if (canvas.GetCacheType() == Drawing::CacheType::ENABLED && !isCached_) {
324         GenerateCache(&canvas, rect);
325     } else if (canvas.GetCacheType() == Drawing::CacheType::DISABLED && isCached_) {
326         ClearCache();
327     }
328 #endif
329     Rect tmpRect;
330     if (rect != nullptr) {
331         tmpRect = *rect;
332     }
333     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
334         PlaybackByBuffer(canvas, &tmpRect);
335     } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
336         PlaybackByVector(canvas, &tmpRect);
337     }
338     if (performanceCaculateOpType_ != 0) {
339         DRAWING_PERFORMANCE_STOP_CACULATE;
340         performanceCaculateOpType_ = 0;
341         LOGI("Drawing Performance Playback end %{public}lld", PerformanceCaculate::GetUpTime());
342     }
343 }
344 
GenerateCache(Canvas * canvas,const Rect * rect)345 void DrawCmdList::GenerateCache(Canvas* canvas, const Rect* rect)
346 {
347 #ifdef ROSEN_OHOS
348     if (isCached_) {
349         LOGD("DrawCmdList::GenerateCache Invoke multiple times");
350         return;
351     }
352 
353     std::lock_guard<std::recursive_mutex> lock(mutex_);
354     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
355         GenerateCacheByBuffer(canvas, rect);
356     } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
357         GenerateCacheByVector(canvas, rect);
358     }
359 #endif
360 }
361 
GetIsCache() const362 bool DrawCmdList::GetIsCache() const
363 {
364     return isCached_;
365 }
366 
SetIsCache(bool isCached)367 void DrawCmdList::SetIsCache(bool isCached)
368 {
369     isCached_ = isCached;
370 }
371 
GetCachedHighContrast() const372 bool DrawCmdList::GetCachedHighContrast() const
373 {
374     return cachedHighContrast_;
375 }
376 
SetCachedHighContrast(bool cachedHighContrast)377 void DrawCmdList::SetCachedHighContrast(bool cachedHighContrast)
378 {
379     cachedHighContrast_ = cachedHighContrast;
380 }
381 
GetReplacedOpList()382 std::vector<std::pair<size_t, size_t>> DrawCmdList::GetReplacedOpList()
383 {
384     return replacedOpListForBuffer_;
385 }
386 
SetReplacedOpList(std::vector<std::pair<size_t,size_t>> replacedOpList)387 void DrawCmdList::SetReplacedOpList(std::vector<std::pair<size_t, size_t>> replacedOpList)
388 {
389     replacedOpListForBuffer_ = replacedOpList;
390 }
391 
UpdateNodeIdToPicture(NodeId nodeId)392 void DrawCmdList::UpdateNodeIdToPicture(NodeId nodeId)
393 {
394     if (drawOpItems_.size() == 0) {
395         return;
396     }
397     for (size_t i = 0; i < drawOpItems_.size(); ++i) {
398         auto opItem = drawOpItems_[i];
399         if (!opItem) {
400             continue;
401         }
402         opItem->SetNodeId(nodeId);
403     }
404 }
405 
ClearCache()406 void DrawCmdList::ClearCache()
407 {
408 #ifdef ROSEN_OHOS
409     // restore the original op
410     for (auto& [index, op] : replacedOpListForVector_) {
411         op.swap(drawOpItems_[index]);
412     }
413     replacedOpListForVector_.clear();
414     replacedOpListForBuffer_.clear();
415     isCached_ = false;
416 #endif
417 }
418 
GenerateCacheByVector(Canvas * canvas,const Rect * rect)419 void DrawCmdList::GenerateCacheByVector(Canvas* canvas, const Rect* rect)
420 {
421 #ifdef ROSEN_OHOS
422     if (drawOpItems_.size() == 0) {
423         return;
424     }
425     uint32_t opSize = drawOpItems_.size();
426     for (auto index = 0u; index < opSize; ++index) {
427         std::shared_ptr<DrawOpItem> op = drawOpItems_[index];
428         if (!op || op->GetType() != DrawOpItem::TEXT_BLOB_OPITEM) {
429             continue;
430         }
431         DrawTextBlobOpItem* textBlobOp = static_cast<DrawTextBlobOpItem*>(op.get());
432         auto replaceCache = textBlobOp->GenerateCachedOpItem(canvas);
433         if (replaceCache) {
434             replacedOpListForVector_.emplace_back(index, op);
435             drawOpItems_[index] = replaceCache;
436         }
437     }
438     isCached_ = true;
439     cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
440 #endif
441 }
442 
GenerateCacheByBuffer(Canvas * canvas,const Rect * rect)443 void DrawCmdList::GenerateCacheByBuffer(Canvas* canvas, const Rect* rect)
444 {
445 #ifdef ROSEN_OHOS
446     if (opAllocator_.GetSize() <= offset_) {
447         return;
448     }
449 
450     size_t offset = offset_;
451     GenerateCachedOpItemPlayer player = { *this, canvas, rect };
452     uint32_t maxOffset = opAllocator_.GetSize();
453     do {
454         void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
455         auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
456         if (curOpItemPtr == nullptr) {
457             LOGE("DrawCmdList::GenerateCacheByBuffer failed, opItem is nullptr");
458             break;
459         }
460         size_t avaliableSize = opAllocator_.GetSize() - offset;
461         bool replaceSuccess = player.GenerateCachedOpItem(curOpItemPtr->GetType(), itemPtr, avaliableSize);
462         if (replaceSuccess) {
463             replacedOpListForBuffer_.push_back({offset, lastOpItemOffset_.value()});
464             itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
465             curOpItemPtr = static_cast<OpItem*>(itemPtr);
466             if (curOpItemPtr == nullptr) {
467                 LOGE("DrawCmdList::GenerateCache failed, opItem is nullptr");
468                 break;
469             }
470         }
471         offset = curOpItemPtr->GetNextOpItemOffset();
472     } while (offset != 0 && offset < maxOffset);
473     isCached_ = true;
474     cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
475 #endif
476 }
477 
PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)478 void DrawCmdList::PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)
479 {
480     if (!drawCmdList) {
481         return;
482     }
483     std::lock_guard<std::recursive_mutex> lock(mutex_);
484     if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
485         std::lock_guard<std::recursive_mutex> lock(drawCmdList->mutex_);
486         drawCmdList->drawOpItems_.insert(drawCmdList->drawOpItems_.end(), drawOpItems_.begin(), drawOpItems_.end());
487         return;
488     }
489 
490     void* addr = opAllocator_.OffsetToAddr(offset_, 0);
491     if (addr == nullptr) {
492         return;
493     }
494 
495     {
496         std::lock_guard<std::mutex> lock(drawCmdList->recordCmdMutex_);
497         drawCmdList->recordCmdVec_.swap(recordCmdVec_);
498     }
499 #ifdef SUPPORT_OHOS_PIXMAP
500     {
501         std::lock_guard<std::mutex> lock(drawCmdList->imageObjectMutex_);
502         drawCmdList->imageObjectVec_.swap(imageObjectVec_);
503     }
504 #endif
505     {
506         std::lock_guard<std::mutex> lock(drawCmdList->imageBaseObjMutex_);
507         drawCmdList->imageBaseObjVec_.swap(imageBaseObjVec_);
508     }
509     size_t size = opAllocator_.GetSize() - offset_;
510     auto imageData = GetAllImageData();
511     auto bitmapData = GetAllBitmapData();
512     drawCmdList->opAllocator_.Add(addr, size);
513     if (imageData.first != nullptr && imageData.second != 0) {
514         drawCmdList->AddImageData(imageData.first, imageData.second);
515     }
516 
517     if (bitmapData.first != nullptr && bitmapData.second != 0) {
518         drawCmdList->AddBitmapData(bitmapData.first, bitmapData.second);
519     }
520 }
521 
PlaybackByVector(Canvas & canvas,const Rect * rect)522 void DrawCmdList::PlaybackByVector(Canvas& canvas, const Rect* rect)
523 {
524     if (drawOpItems_.empty()) {
525         return;
526     }
527     for (auto op : drawOpItems_) {
528         if (op) {
529             op->Playback(&canvas, rect);
530         }
531     }
532     canvas.DetachPaint();
533 }
534 
PlaybackByBuffer(Canvas & canvas,const Rect * rect)535 void DrawCmdList::PlaybackByBuffer(Canvas& canvas, const Rect* rect)
536 {
537     if (opAllocator_.GetSize() <= offset_) {
538         return;
539     }
540     size_t offset = offset_;
541     if (lastOpGenSize_ != opAllocator_.GetSize()) {
542         UnmarshallingPlayer player = { *this };
543         drawOpItems_.clear();
544         do {
545             void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
546             auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
547             if (curOpItemPtr == nullptr) {
548                 break;
549             }
550             uint32_t type = curOpItemPtr->GetType();
551             if (auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset)) {
552                 drawOpItems_.emplace_back(op);
553             }
554             offset = curOpItemPtr->GetNextOpItemOffset();
555         } while (offset != 0);
556         lastOpGenSize_ = opAllocator_.GetSize();
557     }
558     for (auto op : drawOpItems_) {
559         if (op) {
560             op->Playback(&canvas, rect);
561         }
562     }
563     canvas.DetachPaint();
564 }
565 
CountTextBlobNum()566 size_t DrawCmdList::CountTextBlobNum()
567 {
568     size_t textBlobCnt = 0;
569     if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
570         size_t offset = offset_;
571         size_t maxOffset = opAllocator_.GetSize();
572         do {
573             void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
574             auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
575             if (curOpItemPtr == nullptr) {
576                 break;
577             }
578             uint32_t type = curOpItemPtr->GetType();
579             if (type == DrawOpItem::TEXT_BLOB_OPITEM) {
580                 textBlobCnt++;
581             }
582             offset = curOpItemPtr->GetNextOpItemOffset();
583         } while (offset != 0 && offset < maxOffset);
584     }
585     return textBlobCnt;
586 }
587 
Purge()588 void DrawCmdList::Purge()
589 {
590     std::lock_guard<std::recursive_mutex> lock(mutex_);
591     for (auto op : drawOpItems_) {
592         if (!op) {
593             continue;
594         }
595         auto type = op->GetType();
596         if (type == DrawOpItem::PIXELMAP_RECT_OPITEM ||
597             type == DrawOpItem::PIXELMAP_WITH_PARM_OPITEM) {
598             op->Purge();
599         }
600     }
601 }
602 } // namespace Drawing
603 } // namespace Rosen
604 } // namespace OHOS
605