• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 <cstddef>
17 
18 #include "gtest/gtest.h"
19 #include "skia_adapter/skia_canvas.h"
20 #include "skia_adapter/skia_gpu_context.h"
21 #include "skia_adapter/skia_image.h"
22 #include "skia_adapter/skia_surface.h"
23 
24 #include "draw/surface.h"
25 #include "image/image.h"
26 
27 using namespace testing;
28 using namespace testing::ext;
29 
30 namespace OHOS {
31 namespace Rosen {
32 namespace Drawing {
33 class SkiaImageTest : public testing::Test {
34 public:
35     static void SetUpTestCase();
36     static void TearDownTestCase();
37     void SetUp() override;
38     void TearDown() override;
39 };
40 
SetUpTestCase()41 void SkiaImageTest::SetUpTestCase() {}
TearDownTestCase()42 void SkiaImageTest::TearDownTestCase() {}
SetUp()43 void SkiaImageTest::SetUp() {}
TearDown()44 void SkiaImageTest::TearDown() {}
45 
46 /**
47  * @tc.name: BuildFromBitmap001
48  * @tc.desc:
49  * @tc.type: FUNC
50  * @tc.author:
51  */
52 HWTEST_F(SkiaImageTest, BuildFromBitmap001, TestSize.Level1)
53 {
54     Bitmap bitmap;
55     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
56     auto image = skiaImage->BuildFromBitmap(bitmap);
57     EXPECT_EQ(image, false);
58 }
59 
60 /**
61  * @tc.name: MakeRasterData001
62  * @tc.desc: Test MakeRasterData
63  * @tc.type: FUNC
64  * @tc.require: I91EH1
65  */
66 HWTEST_F(SkiaImageTest, MakeRasterData001, TestSize.Level1)
67 {
68     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
69     ImageInfo imageInfo;
70     auto image = skiaImage->MakeRasterData(imageInfo, nullptr, 0);
71     EXPECT_TRUE(image == nullptr);
72     std::shared_ptr<Data> data = std::make_shared<Data>();
73     data->BuildUninitialized(100);
74     auto image2 = skiaImage->MakeRasterData(imageInfo, data, 100);
75     EXPECT_TRUE(image2 == nullptr);
76 }
77 
78 #ifdef RS_ENABLE_GPU
79 /**
80  * @tc.name: MakeFromEncoded001
81  * @tc.desc: Test MakeFromEncoded
82  * @tc.type: FUNC
83  * @tc.require: I91EH1
84  */
85 HWTEST_F(SkiaImageTest, MakeFromEncoded001, TestSize.Level1)
86 {
87     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
88     auto ret = skiaImage->MakeFromEncoded(nullptr);
89     EXPECT_TRUE(!ret);
90 }
91 
92 /**
93  * @tc.name: BuildSubset001
94  * @tc.desc: Test BuildSubset
95  * @tc.type: FUNC
96  * @tc.require: I91EH1
97  */
98 HWTEST_F(SkiaImageTest, BuildSubset001, TestSize.Level1)
99 {
100     auto surface = std::make_unique<SkiaSurface>();
101     surface->FlushAndSubmit(true);
102     Bitmap bitmap;
103     BitmapFormat bitmapFormat { COLORTYPE_RGBA_8888, ALPHATYPE_OPAQUE };
104     bitmap.Build(100, 100, bitmapFormat);
105     ASSERT_TRUE(surface->Bind(bitmap));
106 
107     auto image = surface->GetImageSnapshot();
108     GPUContext context;
109 #ifdef NEW_SKIA
110     GrMockOptions options;
111     context.GetImpl<SkiaGPUContext>()->SetGrContext(GrDirectContext::MakeMock(&options));
112 #endif
113     auto skiaImage = image->GetImpl<SkiaImage>();
114     if (skiaImage) {
115         RectI rect;
116         GPUContext context;
117         skiaImage->BuildSubset(nullptr, rect, context);
118     }
119 }
120 
121 /**
122  * @tc.name: BuildSubset002
123  * @tc.desc: Test BuildSubset002
124  * @tc.type: FUNC
125  * @tc.require: I91EH1
126  */
127 HWTEST_F(SkiaImageTest, BuildSubset002, TestSize.Level1)
128 {
129     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
130     std::unique_ptr<Bitmap> bitmap = std::make_unique<Bitmap>();
131     ASSERT_TRUE(bitmap != nullptr);
132     EXPECT_TRUE(bitmap->Build(151, 150, { ColorType::COLORTYPE_ALPHA_8, AlphaType::ALPHATYPE_OPAQUE }));
133     std::shared_ptr<Image> image = bitmap->MakeImage();
134     ASSERT_TRUE(image != nullptr);
135     RectI rect;
136     GPUContext context;
137     bool result = skiaImage->BuildSubset(image, rect, context);
138     ASSERT_FALSE(result);
139 }
140 
141 /**
142  * @tc.name: BuildFromTexture001
143  * @tc.desc: Test BuildFromTexture
144  * @tc.type: FUNC
145  * @tc.require: I91EH1
146  */
147 HWTEST_F(SkiaImageTest, BuildFromTexture001, TestSize.Level1)
148 {
149     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
150     GPUContext context;
151     TextureInfo textureInfo;
152     textureInfo.SetWidth(10);
153     BitmapFormat bitmapFormat { COLORTYPE_RGBA_8888, ALPHATYPE_OPAQUE };
154     bool ret1 = skiaImage->BuildFromTexture(context, textureInfo, TextureOrigin::TOP_LEFT,
155         bitmapFormat, nullptr, nullptr, nullptr);
156     ASSERT_FALSE(ret1);
157     auto colorSpace = std::make_shared<ColorSpace>(ColorSpace::ColorSpaceType::NO_TYPE);
158     bool ret2 = skiaImage->BuildFromTexture(
159         context, textureInfo, TextureOrigin::TOP_LEFT, bitmapFormat, colorSpace, nullptr, nullptr);
160     ASSERT_FALSE(ret2);
161 }
162 
163 /**
164  * @tc.name: BuildFromTexture002
165  * @tc.desc: Test BuildFromTexture
166  * @tc.type: FUNC
167  * @tc.require: I91EH1
168  */
169 HWTEST_F(SkiaImageTest, BuildFromTexture002, TestSize.Level1)
170 {
171     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
172     GPUContext context;
173     TextureInfo textureInfo;
174     textureInfo.SetWidth(10);
175     BitmapFormat bitmapFormat { COLORTYPE_RGBA_8888, ALPHATYPE_OPAQUE };
176     bool buildFromTexture = skiaImage->BuildFromTexture(
177         context, textureInfo, TextureOrigin::TOP_LEFT, bitmapFormat, nullptr, nullptr, nullptr);
178     ASSERT_FALSE(buildFromTexture);
179 }
180 
181 /**
182  * @tc.name: BuildFromSurface001
183  * @tc.desc: Test BuildFromSurface
184  * @tc.type: FUNC
185  * @tc.require: I91EH1
186  */
187 HWTEST_F(SkiaImageTest, BuildFromSurface001, TestSize.Level1)
188 {
189     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
190     auto skiaCanvas = std::make_shared<SkiaCanvas>();
191     auto gpuContext = skiaCanvas->GetGPUContext();
192     auto surface = Surface::MakeRasterN32Premul(800, 800);
193     BitmapFormat bitmapFormat { COLORTYPE_RGBA_8888, ALPHATYPE_OPAQUE };
194     auto colorSpace = std::make_shared<ColorSpace>(ColorSpace::ColorSpaceType::NO_TYPE);
195     auto ret = skiaImage->BuildFromSurface(*gpuContext, *surface, TextureOrigin::TOP_LEFT, bitmapFormat, colorSpace);
196     ASSERT_TRUE(!ret);
197     ASSERT_TRUE(skiaImage->GetColorSpace() == nullptr);
198 }
199 
200 /**
201  * @tc.name: BuildFromSurface002
202  * @tc.desc: Test BuildFromSurface
203  * @tc.type: FUNC
204  * @tc.require: I91EH1
205  */
206 HWTEST_F(SkiaImageTest, BuildFromSurface002, TestSize.Level1)
207 {
208     auto skiaCanvas = std::make_shared<SkiaCanvas>();
209     auto gpuContext = skiaCanvas->GetGPUContext();
210     BitmapFormat bitmapFormat { COLORTYPE_RGBA_8888, ALPHATYPE_OPAQUE };
211     auto colorSpace = std::make_shared<ColorSpace>(ColorSpace::ColorSpaceType::NO_TYPE);
212     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
213     Surface surFace;
214     auto ret = skiaImage->BuildFromSurface(*gpuContext, surFace, TextureOrigin::TOP_LEFT, bitmapFormat, colorSpace);
215     ASSERT_FALSE(ret);
216 }
217 
218 /**
219  * @tc.name: IsTextureBacked002
220  * @tc.desc: Test GetBackendTexture
221  * @tc.type: FUNC
222  * @tc.require: I91EH1
223  */
224 HWTEST_F(SkiaImageTest, IsTextureBacked002, TestSize.Level1)
225 {
226     auto surface = std::make_unique<SkiaSurface>();
227     surface->FlushAndSubmit(true);
228     Bitmap bitmap;
229     BitmapFormat bitmapFormat { COLORTYPE_RGBA_8888, ALPHATYPE_OPAQUE };
230     bitmap.Build(100, 100, bitmapFormat);
231     ASSERT_TRUE(surface->Bind(bitmap));
232 
233     auto image = surface->GetImageSnapshot();
234     if (image) {
235         auto skiaImage = image->GetImpl<SkiaImage>();
236         if (skiaImage) {
237             ASSERT_TRUE(skiaImage->IsValid(nullptr));
238             ASSERT_TRUE(!skiaImage->IsTextureBacked());
239             ASSERT_TRUE(!skiaImage->IsLazyGenerated());
240             ASSERT_TRUE(skiaImage->CanPeekPixels());
241             ASSERT_TRUE(skiaImage->IsOpaque());
242         }
243     }
244 }
245 
246 /**
247  * @tc.name: IsValid001
248  * @tc.desc: Test IsValid
249  * @tc.type: FUNC
250  * @tc.require: I91EH1
251  */
252 HWTEST_F(SkiaImageTest, IsValid001, TestSize.Level1)
253 {
254     Bitmap bitmap;
255     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
256     ASSERT_TRUE(!skiaImage->IsValid(nullptr));
257     auto ret = skiaImage->BuildFromBitmap(bitmap);
258     if (ret) {
259         ASSERT_TRUE(!skiaImage->IsValid(nullptr));
260         GPUContext context;
261         ASSERT_TRUE(skiaImage->IsValid(&context));
262     }
263 }
264 
265 /**
266  * @tc.name: MakeFromYUVAPixmaps
267  * @tc.desc: Test MakeFromYUVAPixmaps
268  * @tc.type: FUNC
269  * @tc.require: I91EH1
270  */
271 HWTEST_F(SkiaImageTest, MakeFromYUVAPixmaps, TestSize.Level1)
272 {
273     Bitmap bitmap;
274     GPUContext gpuContext;
275     YUVInfo info(100, 100, YUVInfo::PlaneConfig::Y_UV, YUVInfo::SubSampling::K420,
276         YUVInfo::YUVColorSpace::JPEG_FULL_YUVCOLORSPACE,
277         YUVInfo::YUVDataType::UNORM_8);
278     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
279     std::shared_ptr<Image> image = skiaImage->MakeFromYUVAPixmaps(gpuContext, info, nullptr);
280     ASSERT_TRUE(image == nullptr);
281 }
282 
283 
284 /**
285  * @tc.name: BuildFromCompressed
286  * @tc.desc: Test BuildFromCompressed
287  * @tc.type: FUNC
288  * @tc.require: I91EH1
289  */
290 HWTEST_F(SkiaImageTest, BuildFromCompressed, TestSize.Level1)
291 {
292     const int height = 100;
293     const int width = 100;
294     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
295     GPUContext context;
296     bool result = skiaImage->BuildFromCompressed(context, nullptr, width, height, CompressedType::ETC2_RGB8_UNORM);
297     ASSERT_FALSE(result);
298 }
299 
300 /**
301  * @tc.name: SetGrBackendTexture
302  * @tc.desc: Test SetGrBackendTexture
303  * @tc.type: FUNC
304  * @tc.require: I91EH1
305  */
306 HWTEST_F(SkiaImageTest, SetGrBackendTexture, TestSize.Level1)
307 {
308     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
309     ASSERT_TRUE(skiaImage != nullptr);
310     GrBackendTexture skBackendTexture;
311     skiaImage->SetGrBackendTexture(skBackendTexture);
312 }
313 #endif
314 
315 /**
316  * @tc.name: IsLazyGenerated001
317  * @tc.desc: Test IsLazyGenerated
318  * @tc.type: FUNC
319  * @tc.require: I91EH1
320  */
321 HWTEST_F(SkiaImageTest, IsLazyGenerated001, TestSize.Level1)
322 {
323     auto surface = std::make_unique<SkiaSurface>();
324     surface->FlushAndSubmit(true);
325     Bitmap bitmap;
326     BitmapFormat bitmapFormat { COLORTYPE_RGBA_8888, ALPHATYPE_OPAQUE };
327     bitmap.Build(100, 100, bitmapFormat);
328     ASSERT_TRUE(surface->Bind(bitmap));
329 
330     auto image = surface->GetImageSnapshot();
331     auto skiaImage = image->GetImpl<SkiaImage>();
332     ASSERT_TRUE(skiaImage->GetImage() != nullptr);
333     skiaImage->GetColorType();
334     skiaImage->GetAlphaType();
335     ASSERT_TRUE(skiaImage->EncodeToData(EncodedImageFormat::JPEG, 1) != nullptr);
336     ASSERT_TRUE(skiaImage->GetColorSpace() == nullptr);
337     ASSERT_TRUE(skiaImage->MakeRasterImage() != nullptr);
338     ASSERT_TRUE(!skiaImage->IsTextureBacked());
339     ASSERT_TRUE(!skiaImage->IsLazyGenerated());
340     ASSERT_TRUE(skiaImage->CanPeekPixels());
341     ASSERT_TRUE(skiaImage->IsOpaque());
342     Bitmap bitmap2;
343     ASSERT_TRUE(skiaImage->GetROPixels(bitmap2));
344     Pixmap pixmap;
345     skiaImage->ReadPixels(pixmap, 100, 100);
346     Bitmap bitmap3;
347     CubicResampler cubicResampler;
348     SamplingOptions options1 { cubicResampler };
349     ASSERT_TRUE(!skiaImage->ScalePixels(bitmap3, options1, false));
350 }
351 
352 /**
353  * @tc.name: IsLazyGenerated002
354  * @tc.desc: Test IsLazyGenerated
355  * @tc.type: FUNC
356  * @tc.require: I91EH1
357  */
358 HWTEST_F(SkiaImageTest, IsLazyGenerated002, TestSize.Level1)
359 {
360     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
361     ASSERT_TRUE(!skiaImage->IsLazyGenerated());
362 }
363 
364 /**
365  * @tc.name: AsLegacyBitmap001
366  * @tc.desc: Test AsLegacyBitmap
367  * @tc.type: FUNC
368  * @tc.require: I91EH1
369  */
370 HWTEST_F(SkiaImageTest, AsLegacyBitmap001, TestSize.Level1)
371 {
372     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
373     Bitmap bitmap;
374     ASSERT_TRUE(!skiaImage->AsLegacyBitmap(bitmap));
375 }
376 
377 /**
378  * @tc.name: IsOpaque001
379  * @tc.desc: Test IsOpaque
380  * @tc.type: FUNC
381  * @tc.require: I91EH1
382  */
383 HWTEST_F(SkiaImageTest, IsOpaque001, TestSize.Level1)
384 {
385     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
386     ASSERT_TRUE(!skiaImage->IsOpaque());
387 }
388 
389 /**
390  * @tc.name: GetAlphaType001
391  * @tc.desc: Test GetAlphaType
392  * @tc.type: FUNC
393  * @tc.require: I91EH1
394  */
395 HWTEST_F(SkiaImageTest, GetAlphaType001, TestSize.Level1)
396 {
397     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
398     ASSERT_TRUE(skiaImage->GetAlphaType() == AlphaType::ALPHATYPE_UNKNOWN);
399 }
400 
401 /**
402  * @tc.name: GetColorType001
403  * @tc.desc: Test GetColorType
404  * @tc.type: FUNC
405  * @tc.require: I91EH1
406  */
407 HWTEST_F(SkiaImageTest, GetColorType001, TestSize.Level1)
408 {
409     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
410     ASSERT_TRUE(skiaImage->GetColorType() == ColorType::COLORTYPE_UNKNOWN);
411 }
412 
413 /**
414  * @tc.name: GetColorSpace001
415  * @tc.desc: Test GetColorSpace
416  * @tc.type: FUNC
417  * @tc.require: I91EH1
418  */
419 HWTEST_F(SkiaImageTest, GetColorSpace001, TestSize.Level1)
420 {
421     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
422     ASSERT_TRUE(skiaImage->GetColorSpace() == nullptr);
423 }
424 
425 /**
426  * @tc.name: GetImageInfo001
427  * @tc.desc: Test GetImageInfo
428  * @tc.type: FUNC
429  * @tc.require: I91EH1
430  */
431 HWTEST_F(SkiaImageTest, GetImageInfo001, TestSize.Level1)
432 {
433     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
434     ASSERT_TRUE(skiaImage->GetImageInfo().GetWidth() == 0);
435 }
436 
437 /**
438  * @tc.name: IsTextureBacked001
439  * @tc.desc: Test IsTextureBacked
440  * @tc.type: FUNC
441  * @tc.require: I91EH1
442  */
443 HWTEST_F(SkiaImageTest, IsTextureBacked001, TestSize.Level1)
444 {
445     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
446     ASSERT_TRUE(!skiaImage->IsTextureBacked());
447 }
448 
449 /**
450  * @tc.name: ReadPixels001
451  * @tc.desc: Test ReadPixels
452  * @tc.type: FUNC
453  * @tc.require: I91EH1
454  */
455 HWTEST_F(SkiaImageTest, ReadPixels001, TestSize.Level1)
456 {
457     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
458     Pixmap pixmap;
459     ASSERT_FALSE(skiaImage->ReadPixels(pixmap, 0, 0));
460     ImageInfo dstInfo = ImageInfo::MakeN32Premul(100, 100); // 100: width, height
461     ASSERT_FALSE(skiaImage->ReadPixels(dstInfo, nullptr, 100, 100, 100)); // 100: dstRowBytes, srcX, srcY
462 }
463 
464 /**
465  * @tc.name: ScalePixels001
466  * @tc.desc: Test ScalePixels
467  * @tc.type: FUNC
468  * @tc.require: I91EH1
469  */
470 HWTEST_F(SkiaImageTest, ScalePixels001, TestSize.Level1)
471 {
472     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
473     Bitmap bitmap;
474     CubicResampler cubicResampler;
475     SamplingOptions options1 { cubicResampler };
476     ASSERT_TRUE(!skiaImage->ScalePixels(bitmap, options1, false));
477     SamplingOptions options2;
478     ASSERT_TRUE(!skiaImage->ScalePixels(bitmap, options2, true));
479 }
480 
481 /**
482  * @tc.name: EncodeToData001
483  * @tc.desc: Test EncodeToData
484  * @tc.type: FUNC
485  * @tc.require: I91EH1
486  */
487 HWTEST_F(SkiaImageTest, EncodeToData001, TestSize.Level1)
488 {
489     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
490     ASSERT_TRUE(skiaImage->EncodeToData(EncodedImageFormat::JPEG, 1) == nullptr);
491 }
492 
493 /**
494  * @tc.name: MakeRasterImage001
495  * @tc.desc: Test MakeRasterImage
496  * @tc.type: FUNC
497  * @tc.require: I91EH1
498  */
499 HWTEST_F(SkiaImageTest, MakeRasterImage001, TestSize.Level1)
500 {
501     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
502     ASSERT_TRUE(skiaImage->MakeRasterImage() == nullptr);
503 }
504 
505 /**
506  * @tc.name: GetROPixels001
507  * @tc.desc: Test GetROPixels
508  * @tc.type: FUNC
509  * @tc.require: I91EH1
510  */
511 HWTEST_F(SkiaImageTest, GetROPixels001, TestSize.Level1)
512 {
513     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
514     Bitmap bitmap;
515     ASSERT_TRUE(!skiaImage->GetROPixels(bitmap));
516 }
517 
518 /**
519  * @tc.name: CanPeekPixels001
520  * @tc.desc: Test CanPeekPixels
521  * @tc.type: FUNC
522  * @tc.require: I91EH1
523  */
524 HWTEST_F(SkiaImageTest, CanPeekPixels001, TestSize.Level1)
525 {
526     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
527     ASSERT_TRUE(!skiaImage->CanPeekPixels());
528 }
529 
530 /**
531  * @tc.name: GetImage001
532  * @tc.desc: Test GetImage
533  * @tc.type: FUNC
534  * @tc.require: I91EH1
535  */
536 HWTEST_F(SkiaImageTest, GetImage001, TestSize.Level1)
537 {
538     sk_sp<SkImage> img;
539     SkiaImage skiaImage;
540     skiaImage.SetSkImage(img);
541     ASSERT_TRUE(skiaImage.GetImage() == img);
542 }
543 
544 /**
545  * @tc.name: MakeFromRaster
546  * @tc.desc: Test MakeFromRaster
547  * @tc.type: FUNC
548  * @tc.require: I91EH1
549  */
550 HWTEST_F(SkiaImageTest, MakeFromRaster, TestSize.Level1)
551 {
552     Pixmap pixmap;
553     std::shared_ptr<SkiaImage> skiaImage = std::make_shared<SkiaImage>();
554     std::shared_ptr<Image> image = skiaImage->MakeFromRaster(pixmap, nullptr, nullptr);
555     ASSERT_TRUE(image == nullptr);
556 }
557 
558 } // namespace Drawing
559 } // namespace Rosen
560 } // namespace OHOS