1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "dfx/ui_screenshot.h"
17a3e0fd82Sopenharmony_ci#if ENABLE_DEBUG
18a3e0fd82Sopenharmony_ci#include "iwindows_manager.h"
19a3e0fd82Sopenharmony_ci#include "common/screen.h"
20a3e0fd82Sopenharmony_ci#include "draw/draw_utils.h"
21a3e0fd82Sopenharmony_ci#include "gfx_utils/color.h"
22a3e0fd82Sopenharmony_ci#include "gfx_utils/file.h"
23a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_log.h"
24a3e0fd82Sopenharmony_ci#include "gfx_utils/image_info.h"
25a3e0fd82Sopenharmony_ci#include "securec.h"
26a3e0fd82Sopenharmony_ci
27a3e0fd82Sopenharmony_cinamespace OHOS {
28a3e0fd82Sopenharmony_ciclass UIScreenshotListener : public IWindowsManager::ScreenshotListener {
29a3e0fd82Sopenharmony_cipublic:
30a3e0fd82Sopenharmony_ci    UIScreenshotListener() : filePath_(nullptr) {}
31a3e0fd82Sopenharmony_ci
32a3e0fd82Sopenharmony_ci    virtual ~UIScreenshotListener()
33a3e0fd82Sopenharmony_ci    {
34a3e0fd82Sopenharmony_ci        if (filePath_ != nullptr) {
35a3e0fd82Sopenharmony_ci            UIFree(reinterpret_cast<void*>(filePath_));
36a3e0fd82Sopenharmony_ci            filePath_ = nullptr;
37a3e0fd82Sopenharmony_ci        }
38a3e0fd82Sopenharmony_ci    }
39a3e0fd82Sopenharmony_ci
40a3e0fd82Sopenharmony_ci    void OnScreenshotEnd(uint8_t* virAddr, uint32_t width, uint32_t height,
41a3e0fd82Sopenharmony_ci                         ImagePixelFormat format, uint32_t stride) override
42a3e0fd82Sopenharmony_ci    {
43a3e0fd82Sopenharmony_ci        if ((virAddr == nullptr) || ((format != IMAGE_PIXEL_FORMAT_ARGB1555) &&
44a3e0fd82Sopenharmony_ci            (format != IMAGE_PIXEL_FORMAT_ARGB8888)) || (width == 0) || (height == 0)) {
45a3e0fd82Sopenharmony_ci            return;
46a3e0fd82Sopenharmony_ci        }
47a3e0fd82Sopenharmony_ci
48a3e0fd82Sopenharmony_ci        ImageHeader header = {0};
49a3e0fd82Sopenharmony_ci        header.colorMode = ARGB8888;
50a3e0fd82Sopenharmony_ci        header.width = width;
51a3e0fd82Sopenharmony_ci        header.height = height;
52a3e0fd82Sopenharmony_ci
53a3e0fd82Sopenharmony_ci        unlink(filePath_);
54a3e0fd82Sopenharmony_ci        int32_t fd = open(filePath_, O_RDWR | O_CREAT, DEFAULT_FILE_PERMISSION);
55a3e0fd82Sopenharmony_ci        UIFree(reinterpret_cast<void*>(filePath_));
56a3e0fd82Sopenharmony_ci        filePath_ = nullptr;
57a3e0fd82Sopenharmony_ci        if (fd < 0) {
58a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("UIScreenshotListener::OnScreenshotEnd open file failed Err!\n");
59a3e0fd82Sopenharmony_ci            return;
60a3e0fd82Sopenharmony_ci        }
61a3e0fd82Sopenharmony_ci
62a3e0fd82Sopenharmony_ci        if (write(fd, &header, sizeof(ImageHeader)) != sizeof(ImageHeader)) {
63a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("UIScreenshotListener::OnScreenshotEnd write image header failed Err!\n");
64a3e0fd82Sopenharmony_ci            close(fd);
65a3e0fd82Sopenharmony_ci            return;
66a3e0fd82Sopenharmony_ci        }
67a3e0fd82Sopenharmony_ci
68a3e0fd82Sopenharmony_ci        uint32_t row = MAX_MALLOC_SIZE / width;
69a3e0fd82Sopenharmony_ci        row = (row == 0) ? 1 : row;
70a3e0fd82Sopenharmony_ci        uint32_t size = row * width * sizeof(uint32_t);
71a3e0fd82Sopenharmony_ci        uint32_t* argb8888Addr = static_cast<uint32_t*>(UIMalloc(size));
72a3e0fd82Sopenharmony_ci        if (argb8888Addr == nullptr) {
73a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("UIScreenshotListener::OnScreenshotEnd memory allocation failed Err!");
74a3e0fd82Sopenharmony_ci            close(fd);
75a3e0fd82Sopenharmony_ci            return;
76a3e0fd82Sopenharmony_ci        }
77a3e0fd82Sopenharmony_ci
78a3e0fd82Sopenharmony_ci        while (height >= row) {
79a3e0fd82Sopenharmony_ci            WriteBlockToFile(fd, argb8888Addr, virAddr, row, width, format, stride);
80a3e0fd82Sopenharmony_ci            height -= row;
81a3e0fd82Sopenharmony_ci        }
82a3e0fd82Sopenharmony_ci        if (height != 0) {
83a3e0fd82Sopenharmony_ci            WriteBlockToFile(fd, argb8888Addr, virAddr, height, width, format, stride);
84a3e0fd82Sopenharmony_ci        }
85a3e0fd82Sopenharmony_ci        UIFree(reinterpret_cast<void*>(argb8888Addr));
86a3e0fd82Sopenharmony_ci        close(fd);
87a3e0fd82Sopenharmony_ci    }
88a3e0fd82Sopenharmony_ci
89a3e0fd82Sopenharmony_ci    void SetFilePath(char* path)
90a3e0fd82Sopenharmony_ci    {
91a3e0fd82Sopenharmony_ci        if (filePath_ != nullptr) {
92a3e0fd82Sopenharmony_ci            UIFree(reinterpret_cast<void*>(filePath_));
93a3e0fd82Sopenharmony_ci        }
94a3e0fd82Sopenharmony_ci        filePath_ = path;
95a3e0fd82Sopenharmony_ci    }
96a3e0fd82Sopenharmony_ci
97a3e0fd82Sopenharmony_ciprivate:
98a3e0fd82Sopenharmony_ci    static constexpr uint8_t DEFAULT_COLOR_SIZE = 4;
99a3e0fd82Sopenharmony_ci    static constexpr uint16_t MAX_MALLOC_SIZE = 2048; // unit: 4 bytes
100a3e0fd82Sopenharmony_ci    char* filePath_;
101a3e0fd82Sopenharmony_ci
102a3e0fd82Sopenharmony_ci    bool WriteBlockToFile(int32_t fd, uint32_t* buffer, uint8_t*& startAddr, uint32_t row,
103a3e0fd82Sopenharmony_ci                          uint32_t width, ImagePixelFormat format, uint32_t stride) const
104a3e0fd82Sopenharmony_ci    {
105a3e0fd82Sopenharmony_ci        uint32_t* argb8888Addr = buffer;
106a3e0fd82Sopenharmony_ci        for (uint32_t r = 0; r < row; ++r) {
107a3e0fd82Sopenharmony_ci            if (format == IMAGE_PIXEL_FORMAT_ARGB1555) {
108a3e0fd82Sopenharmony_ci                uint16_t* temp = reinterpret_cast<uint16_t*>(startAddr);
109a3e0fd82Sopenharmony_ci                for (uint32_t i = 0; i < width; ++i) {
110a3e0fd82Sopenharmony_ci                    buffer[i] = PixelFormatUtils::ARGB1555ToARGB8888(*temp++);
111a3e0fd82Sopenharmony_ci                }
112a3e0fd82Sopenharmony_ci            } else if (format == IMAGE_PIXEL_FORMAT_ARGB8888) {
113a3e0fd82Sopenharmony_ci                if (memcpy_s(buffer, width * DEFAULT_COLOR_SIZE, startAddr, width * DEFAULT_COLOR_SIZE) != EOK) {
114a3e0fd82Sopenharmony_ci                    GRAPHIC_LOGE("memcpy_s error!");
115a3e0fd82Sopenharmony_ci                }
116a3e0fd82Sopenharmony_ci            }
117a3e0fd82Sopenharmony_ci            startAddr += stride;
118a3e0fd82Sopenharmony_ci            buffer += width;
119a3e0fd82Sopenharmony_ci        }
120a3e0fd82Sopenharmony_ci
121a3e0fd82Sopenharmony_ci        uint32_t blockSize = row * width * sizeof(uint32_t);
122a3e0fd82Sopenharmony_ci        if (static_cast<uint32_t>(write(fd, argb8888Addr, blockSize)) != blockSize) {
123a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("UIScreenshotListener::WriteBlockToFile wrong amount of written data Err!");
124a3e0fd82Sopenharmony_ci            return false;
125a3e0fd82Sopenharmony_ci        }
126a3e0fd82Sopenharmony_ci        return true;
127a3e0fd82Sopenharmony_ci    }
128a3e0fd82Sopenharmony_ci};
129a3e0fd82Sopenharmony_ci
130a3e0fd82Sopenharmony_ciUIScreenshot::~UIScreenshot()
131a3e0fd82Sopenharmony_ci{
132a3e0fd82Sopenharmony_ci    if (screenshotListener_ != nullptr) {
133a3e0fd82Sopenharmony_ci        delete screenshotListener_;
134a3e0fd82Sopenharmony_ci        screenshotListener_ = nullptr;
135a3e0fd82Sopenharmony_ci    }
136a3e0fd82Sopenharmony_ci}
137a3e0fd82Sopenharmony_ci
138a3e0fd82Sopenharmony_ciUIScreenshot* UIScreenshot::GetInstance()
139a3e0fd82Sopenharmony_ci{
140a3e0fd82Sopenharmony_ci    static UIScreenshot instance;
141a3e0fd82Sopenharmony_ci    return &instance;
142a3e0fd82Sopenharmony_ci}
143a3e0fd82Sopenharmony_ci
144a3e0fd82Sopenharmony_cibool UIScreenshot::ScreenshotToFile(const char* path)
145a3e0fd82Sopenharmony_ci{
146a3e0fd82Sopenharmony_ci    IWindowsManager* manager = IWindowsManager::GetInstance();
147a3e0fd82Sopenharmony_ci    if (screenshotListener_ == nullptr) {
148a3e0fd82Sopenharmony_ci        screenshotListener_ = new UIScreenshotListener();
149a3e0fd82Sopenharmony_ci        if (screenshotListener_ == nullptr) {
150a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("UIScreenshot::ScreenshotToFile register screenshot listener failed Err!\n");
151a3e0fd82Sopenharmony_ci            return false;
152a3e0fd82Sopenharmony_ci        }
153a3e0fd82Sopenharmony_ci        manager->SetScreenshotListener(screenshotListener_);
154a3e0fd82Sopenharmony_ci    }
155a3e0fd82Sopenharmony_ci
156a3e0fd82Sopenharmony_ci    const char* srcPath = (path == nullptr) ? DEFAULT_SCREENSHOT_PATH : path;
157a3e0fd82Sopenharmony_ci    uint32_t pathLength = strlen(srcPath);
158a3e0fd82Sopenharmony_ci    char* destPath = static_cast<char*>(UIMalloc(pathLength + 1));
159a3e0fd82Sopenharmony_ci    if (destPath == nullptr) {
160a3e0fd82Sopenharmony_ci        return false;
161a3e0fd82Sopenharmony_ci    }
162a3e0fd82Sopenharmony_ci
163a3e0fd82Sopenharmony_ci    if (memcpy_s(destPath, pathLength + 1, srcPath, pathLength) != EOK) {
164a3e0fd82Sopenharmony_ci        UIFree(reinterpret_cast<void*>(destPath));
165a3e0fd82Sopenharmony_ci        return false;
166a3e0fd82Sopenharmony_ci    }
167a3e0fd82Sopenharmony_ci    destPath[pathLength] = '\0';
168a3e0fd82Sopenharmony_ci    screenshotListener_->SetFilePath(destPath);
169a3e0fd82Sopenharmony_ci    manager->Screenshot();
170a3e0fd82Sopenharmony_ci    return true;
171a3e0fd82Sopenharmony_ci}
172a3e0fd82Sopenharmony_ci} // namespace OHOS
173a3e0fd82Sopenharmony_ci#endif // ENABLE_DEBUG
174