efl

Форк
0
/
draw_convert.c 
618 строк · 17.7 Кб
1
#include "draw.h"
2
#include "draw_private.h"
3
#include "../rg_etc/rg_etc1.h"
4

5
#ifdef BUILD_NEON
6
#include <arm_neon.h>
7
#endif
8

9
#if DIV_USING_BITSHIFT
10
# define DEFINE_DIVIDER(div) const int pow2 = _pow2_geq((div) << 10); const int numerator = (1 << pow2) / (div);
11
# define DIVIDE(val) (((val) * numerator) >> pow2)
12
#else
13
# define DEFINE_DIVIDER(div) const int divider = (div);
14
# define DIVIDE(val) ((val) / divider)
15
#endif
16

17
#define CONVERT_RGB_565_TO_RGB_888(s) \
18
        (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
19
         ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
20
         ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)))
21

22
#define CONVERT_A5P_TO_A8(s) \
23
        ((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7))
24

25
#define CONVERT_ARGB_8888_TO_A_8(s)	((s) >> 24)
26

27
// finds smallest power of 2 above val
28
static int
29
_pow2_geq(int val)
30
{
31
   for (int n = 0; n < 32; n++)
32
     if (val <= (1 << n))
33
       return n;
34

35
   return 32; // impossible
36
}
37

38
static Eina_Bool
39
_convert_gry8_to_argb8888(void *dst, const void *src, int w, int h,
40
                          int src_stride, int dst_stride, Eina_Bool has_alpha,
41
                          Efl_Gfx_Colorspace srccs EINA_UNUSED,
42
                          Efl_Gfx_Colorspace dstcs EINA_UNUSED)
43
{
44
   const uint8_t *in = src;
45
   uint32_t *out = dst;
46
   int in_step, out_step, x, y;
47

48
   if (!src_stride) src_stride = w;
49
   if (!dst_stride) dst_stride = w * 4;
50
   in_step = src_stride;
51
   out_step = dst_stride / 4;
52

53
   if (has_alpha)
54
     {
55
        // transparent white
56
        for (y = 0; y < h; y++)
57
          {
58
             for (x = 0; x < w; x++)
59
               {
60
                  int c = in[x];
61
                  out[x] = DRAW_ARGB_JOIN(c, c, c, c);
62
               }
63
             in += in_step;
64
             out += out_step;
65
          }
66
     }
67
   else
68
     {
69
        // opaque grayscale
70
        for (y = 0; y < h; y++)
71
          {
72
             for (x = 0; x < w; x++)
73
               {
74
                  int c = in[x];
75
                  out[x] = DRAW_ARGB_JOIN(0xFF, c, c, c);
76
               }
77
             in += in_step;
78
             out += out_step;
79
          }
80
     }
81

82
   return EINA_TRUE;
83
}
84

85
static Eina_Bool
86
_convert_agry88_to_argb8888(void *dst, const void *src, int w, int h,
87
                            int src_stride, int dst_stride, Eina_Bool has_alpha,
88
                            Efl_Gfx_Colorspace srccs EINA_UNUSED,
89
                            Efl_Gfx_Colorspace dstcs EINA_UNUSED)
90
{
91
   const uint16_t *in = src;
92
   uint32_t *out = dst;
93
   int in_step, out_step, x, y;
94

95
   if (!src_stride) src_stride = w * 2;
96
   if (!dst_stride) dst_stride = w * 4;
97
   in_step = src_stride / 2;
98
   out_step = dst_stride / 4;
99

100
   if (has_alpha)
101
     {
102
        for (y = 0; y < h; y++)
103
          {
104
             for (x = 0; x < w; x++)
105
               {
106
                  int c = in[x] & 0xFF;
107
                  int a = in[x] >> 8;
108
                  out[x] = DRAW_ARGB_JOIN(a, c, c, c);
109
               }
110
             in += in_step;
111
             out += out_step;
112
          }
113
     }
114
   else
115
     {
116
        for (y = 0; y < h; y++)
117
          {
118
             for (x = 0; x < w; x++)
119
               {
120
                  int c = in[x] & 0xFF;
121
                  out[x] = DRAW_ARGB_JOIN(0xFF, c, c, c);
122
               }
123
             in += in_step;
124
             out += out_step;
125
          }
126
     }
127

128
   return EINA_TRUE;
129
}
130

131
static Eina_Bool
132
_convert_argb8888_to_gry8(void *dst, const void *src, int w, int h,
133
                          int src_stride, int dst_stride, Eina_Bool has_alpha,
134
                          Efl_Gfx_Colorspace srccs EINA_UNUSED,
135
                          Efl_Gfx_Colorspace dstcs EINA_UNUSED)
136
{
137
   const uint32_t *in = src;
138
   uint8_t *out = dst;
139
   int in_step, out_step, x, y;
140
#if RGBA2LUM_WEIGHTED
141
   const int WR = 299;
142
   const int WG = 587;
143
   const int WB = 114;
144
#else
145
   const int WR = 1;
146
   const int WG = 1;
147
   const int WB = 1;
148
#endif
149
   DEFINE_DIVIDER(WR + WG + WB);
150

151
   if (!src_stride) src_stride = w * 4;
152
   if (!dst_stride) dst_stride = w;
153
   in_step = src_stride / 4;
154
   out_step = dst_stride;
155

156
   if (has_alpha)
157
     {
158
        // copy only alpha
159
        for (y = 0; y < h; y++)
160
          {
161
             for (x = 0; x < w; x++)
162
               out[x] = A_VAL(in + x);
163
             in += in_step;
164
             out += out_step;
165
          }
166
     }
167
   else
168
     {
169
        // copy only color to grayscale
170
        for (y = 0; y < h; y++)
171
          {
172
             for (x = 0; x < w; x++)
173
               out[x] = DIVIDE((R_VAL(in + x) * WR) + (G_VAL(in + x) * WG) + (B_VAL(in + x) * WB));
174
             in += in_step;
175
             out += out_step;
176
          }
177
     }
178

179
   return EINA_TRUE;
180
}
181

182
static Eina_Bool
183
_convert_argb8888_to_agry88(void *dst, const void *src, int w, int h,
184
                            int src_stride, int dst_stride, Eina_Bool has_alpha,
185
                            Efl_Gfx_Colorspace srccs EINA_UNUSED,
186
                            Efl_Gfx_Colorspace dstcs EINA_UNUSED)
187
{
188
   const uint32_t *in = src;
189
   uint16_t *out = dst;
190
   int in_step, out_step, x, y;
191
#if RGBA2LUM_WEIGHTED
192
   const int WR = 299;
193
   const int WG = 587;
194
   const int WB = 114;
195
#else
196
   const int WR = 1;
197
   const int WG = 1;
198
   const int WB = 1;
199
#endif
200
   DEFINE_DIVIDER(WR + WG + WB);
201

202
   if (!src_stride) src_stride = w * 4;
203
   if (!dst_stride) dst_stride = w * 2;
204
   in_step = src_stride / 4;
205
   out_step = dst_stride / 2;
206

207
   if (has_alpha)
208
     {
209
        // copy only alpha
210
        for (y = 0; y < h; y++)
211
          {
212
             for (x = 0; x < w; x++)
213
               {
214
                  int a = A_VAL(in + x);
215
                  int c = DIVIDE((R_VAL(in + x) * WR) + (G_VAL(in + x) * WG) + (B_VAL(in + x) * WB));
216
                  out[x] = (a << 8) | c;
217
               }
218
             in += in_step;
219
             out += out_step;
220
          }
221
     }
222
   else
223
     {
224
        // copy only color to grayscale
225
        for (y = 0; y < h; y++)
226
          {
227
             for (x = 0; x < w; x++)
228
               {
229
                  int c = DIVIDE((R_VAL(in + x) * WR) + (G_VAL(in + x) * WG) + (B_VAL(in + x) * WB));
230
                  out[x] = 0xFF00 | c;
231
               }
232
             in += in_step;
233
             out += out_step;
234
          }
235
     }
236

237
   return EINA_TRUE;
238
}
239

240
static Eina_Bool
241
_convert_rgb565_a5p_to_argb8888(void *dst, const void *src, int w, int h,
242
                                int src_stride, int dst_stride, Eina_Bool has_alpha,
243
                                Efl_Gfx_Colorspace srccs EINA_UNUSED,
244
                                Efl_Gfx_Colorspace dstcs EINA_UNUSED)
245
{
246
   const uint16_t *in = src;
247
   const uint8_t *in_alpha;
248
   uint32_t *out = dst;
249
   int in_step, out_step, a_step, x, y;
250

251
   if (!src_stride) src_stride = w * 2;
252
   if (!dst_stride) dst_stride = w * 4;
253
   in_step = src_stride / 2;
254
   a_step = src_stride;
255
   out_step = dst_stride / 4;
256

257
   // no region support (2 planes): basic safety check (can't verify h)
258
   EINA_SAFETY_ON_FALSE_RETURN_VAL((src_stride == (w * 2)) && (dst_stride == (w * 4)), EINA_FALSE);
259

260
   if (has_alpha)
261
     {
262
        in_alpha = ((uint8_t *) in) + (src_stride * h);
263
        for (y = 0; y < h; y++)
264
          {
265
             for (x = 0; x < w; x++)
266
               {
267
                  int a = CONVERT_A5P_TO_A8(in_alpha[x]);
268
                  int c = CONVERT_RGB_565_TO_RGB_888(in[x]);
269
                  out[x] = (a << 24) | c;
270
               }
271
             in_alpha += a_step;
272
             in += in_step;
273
             out += out_step;
274
          }
275
     }
276
   else
277
     {
278
        for (y = 0; y < h; y++)
279
          {
280
             for (x = 0; x < w; x++)
281
               {
282
                  int c = CONVERT_RGB_565_TO_RGB_888(in[x]);
283
                  out[x] = 0xFF000000 | c;
284
               }
285
             in += in_step;
286
             out += out_step;
287
          }
288
     }
289

290
   return EINA_TRUE;
291
}
292

293
static Eina_Bool
294
_convert_etc2_rgb8_to_argb8888(void *dst, const void *src, int w, int h,
295
                               int src_stride, int dst_stride, Eina_Bool has_alpha,
296
                               Efl_Gfx_Colorspace srccs EINA_UNUSED,
297
                               Efl_Gfx_Colorspace dstcs EINA_UNUSED)
298
{
299
   const uint8_t *in = src;
300
   uint32_t *out = dst;
301
   int out_step, x, y, k;
302
   unsigned int bgra[16];
303

304
   EINA_SAFETY_ON_FALSE_RETURN_VAL(!(w & 3) && !(h & 3), EINA_FALSE);
305
   EINA_SAFETY_ON_FALSE_RETURN_VAL(!has_alpha, EINA_FALSE);
306

307
   // jumps lines 4 by 4
308
   if (!src_stride) src_stride = w * 8 / 4;
309
   if (!dst_stride) dst_stride = w * 4;
310
   out_step = dst_stride / 4;
311

312
   for (y = 0; y < h; y += 4)
313
     {
314
        for (x = 0; x < w; x += 4, in += 8)
315
          {
316
             rg_etc2_rgb8_decode_block(in, bgra);
317
             for (k = 0; k < 4; k++)
318
               memcpy(out + x + k * out_step, bgra + (k * 4), 16);
319
          }
320
     }
321

322
   return EINA_TRUE;
323
}
324

325
static Eina_Bool
326
_convert_etc2_rgba8_to_argb8888(void *dst, const void *src, int w, int h,
327
                                int src_stride, int dst_stride, Eina_Bool has_alpha,
328
                                Efl_Gfx_Colorspace srccs EINA_UNUSED,
329
                                Efl_Gfx_Colorspace dstcs EINA_UNUSED)
330
{
331
   const uint8_t *in = src;
332
   uint32_t *out = dst;
333
   int out_step, x, y, k;
334
   unsigned int bgra[16];
335

336
   EINA_SAFETY_ON_FALSE_RETURN_VAL(!(w & 3) && !(h & 3), EINA_FALSE);
337
   EINA_SAFETY_ON_FALSE_RETURN_VAL(!has_alpha, EINA_FALSE);
338

339
   // jumps lines 4 by 4
340
   if (!src_stride) src_stride = w * 16 / 4;
341
   if (!dst_stride) dst_stride = w * 4;
342
   out_step = dst_stride / 4;
343

344
   for (y = 0; y < h; y += 4)
345
     {
346
        for (x = 0; x < w; x += 4, in += 16)
347
          {
348
             rg_etc2_rgba8_decode_block(in, bgra);
349
             for (k = 0; k < 4; k++)
350
               memcpy(out + x + k * out_step, bgra + (k * 4), 16);
351
          }
352
        out += out_step * 4;
353
     }
354

355
   return EINA_TRUE;
356
}
357

358
static Eina_Bool
359
_convert_etc1_alpha_to_argb8888(void *dst, const void *src, int w, int h,
360
                                int src_stride, int dst_stride, Eina_Bool has_alpha,
361
                                Efl_Gfx_Colorspace srccs EINA_UNUSED,
362
                                Efl_Gfx_Colorspace dstcs EINA_UNUSED)
363
{
364
   const uint8_t *in = src, *in_alpha;
365
   uint32_t *out = dst;
366
   int out_step, x, y, j, k;
367
   unsigned int bgra[16], alpha[16];
368

369
   EINA_SAFETY_ON_FALSE_RETURN_VAL(!(w & 3) && !(h & 3), EINA_FALSE);
370
   EINA_SAFETY_ON_FALSE_RETURN_VAL(!has_alpha, EINA_FALSE);
371

372
   // jumps lines 4 by 4
373
   if (!src_stride) src_stride = w * 8 / 4;
374
   if (!dst_stride) dst_stride = w * 4;
375
   out_step = dst_stride / 4;
376

377
   in_alpha = in + src_stride * h;
378

379
   for (y = 0; y < h; y += 4)
380
     {
381
        for (x = 0; x < w; x += 4, in += 8, in_alpha += 8)
382
          {
383
             rg_etc2_rgba8_decode_block(in, bgra);
384
             rg_etc2_rgba8_decode_block(in_alpha, alpha);
385
             for (k = 0; k < 4; k++)
386
               for (j = 0; j < 4; j++)
387
                 {
388
                    int a = (alpha[(k * 4) + j] & 0x00FF00) >> 8;
389
                    int c = (bgra[(k * 4) + j] & 0x00FFFFFF);
390
                    out[(k * out_step) + j] = (a << 24) | c;
391
                 }
392
          }
393
        out += out_step;
394
     }
395

396
   return EINA_TRUE;
397
}
398

399
static Eina_Bool
400
_convert_generic_two_pass(void *dst, const void *src, int w, int h,
401
                          int src_stride, int dst_stride, Eina_Bool has_alpha,
402
                          Efl_Gfx_Colorspace srccs, Efl_Gfx_Colorspace dstcs)
403
{
404
   Cspace_Convert_Func to_argb = efl_draw_convert_func_get(srccs, EFL_GFX_COLORSPACE_ARGB8888, NULL);
405
   Cspace_Convert_Func from_argb = efl_draw_convert_func_get(EFL_GFX_COLORSPACE_ARGB8888, dstcs, NULL);
406
   uint32_t *argb;
407

408
   EINA_SAFETY_ON_NULL_RETURN_VAL(to_argb, EINA_FALSE);
409
   EINA_SAFETY_ON_NULL_RETURN_VAL(from_argb, EINA_FALSE);
410

411
   argb = malloc(w * h * sizeof(uint32_t));
412
   if (!argb) return EINA_FALSE;
413

414
   if (!to_argb(argb, src, w, h, src_stride, 0, has_alpha, srccs, EFL_GFX_COLORSPACE_ARGB8888))
415
     goto fail;
416

417
   if (!from_argb(dst, argb, w, h, 0, dst_stride, has_alpha, EFL_GFX_COLORSPACE_ARGB8888, dstcs))
418
     goto fail;
419

420
   free(argb);
421
   return EINA_TRUE;
422

423
fail:
424
   free(argb);
425
   return EINA_FALSE;
426
}
427

428
Cspace_Convert_Func
429
efl_draw_convert_func_get(Efl_Gfx_Colorspace srccs, Efl_Gfx_Colorspace dstcs,
430
                          Eina_Bool *region_can)
431
{
432
   Eina_Bool reg1 = EINA_FALSE, reg2 = EINA_FALSE;
433
   Cspace_Convert_Func to_argb = NULL;
434
   Cspace_Convert_Func from_argb = NULL;
435

436
   EINA_SAFETY_ON_FALSE_RETURN_VAL(srccs != dstcs, NULL);
437

438
   if ((dstcs != EFL_GFX_COLORSPACE_ARGB8888) && (srccs != EFL_GFX_COLORSPACE_ARGB8888))
439
     {
440
        to_argb = efl_draw_convert_func_get(srccs, EFL_GFX_COLORSPACE_ARGB8888, &reg1);
441
        from_argb = efl_draw_convert_func_get(EFL_GFX_COLORSPACE_ARGB8888, dstcs, &reg2);
442
     }
443

444
   if (region_can) *region_can = EINA_TRUE;
445

446
   switch (srccs)
447
     {
448
      case EFL_GFX_COLORSPACE_ARGB8888:
449
        if (dstcs == EFL_GFX_COLORSPACE_GRY8)
450
          return _convert_argb8888_to_gry8;
451
        if (dstcs == EFL_GFX_COLORSPACE_AGRY88)
452
          return _convert_argb8888_to_agry88;
453
        break;
454

455
      case EFL_GFX_COLORSPACE_GRY8:
456
        if (dstcs == EFL_GFX_COLORSPACE_ARGB8888)
457
          return _convert_gry8_to_argb8888;
458
        break;
459

460
      case EFL_GFX_COLORSPACE_AGRY88:
461
        if (dstcs == EFL_GFX_COLORSPACE_ARGB8888)
462
          return _convert_agry88_to_argb8888;
463
        break;
464

465
      case EFL_GFX_COLORSPACE_RGB565_A5P:
466
        if (dstcs == EFL_GFX_COLORSPACE_ARGB8888)
467
          {
468
             // we could do regions, but we would need a pointer to the alpha plane.
469
             if (region_can) *region_can = EINA_FALSE;
470
             return _convert_rgb565_a5p_to_argb8888;
471
          }
472
        break;
473

474
      case EFL_GFX_COLORSPACE_YCBCR422P601_PL:
475
      case EFL_GFX_COLORSPACE_YCBCR422601_PL:
476
      case EFL_GFX_COLORSPACE_YCBCR420NV12601_PL:
477
      case EFL_GFX_COLORSPACE_YCBCR420TM12601_PL:
478
      case EFL_GFX_COLORSPACE_YCBCR422P709_PL:
479
         /* FIXME */
480

481
      case EFL_GFX_COLORSPACE_ETC1:
482
      case EFL_GFX_COLORSPACE_RGB8_ETC2:
483
        if (dstcs == EFL_GFX_COLORSPACE_ARGB8888)
484
          {
485
             // we could do regions, but only if they are 4x4 aligned.
486
             if (region_can) *region_can = EINA_FALSE;
487
             return _convert_etc2_rgb8_to_argb8888;
488
          }
489
        break;
490

491
      case EFL_GFX_COLORSPACE_RGBA8_ETC2_EAC:
492
        if (dstcs == EFL_GFX_COLORSPACE_ARGB8888)
493
          {
494
             // we could do regions, but only if they are 4x4 aligned.
495
             if (region_can) *region_can = EINA_FALSE;
496
             return _convert_etc2_rgba8_to_argb8888;
497
          }
498
        break;
499

500
      case EFL_GFX_COLORSPACE_ETC1_ALPHA:
501
        if (dstcs == EFL_GFX_COLORSPACE_ARGB8888)
502
          {
503
             // we could do regions, but only if they are 4x4 aligned.
504
             if (region_can) *region_can = EINA_FALSE;
505
             return _convert_etc1_alpha_to_argb8888;
506
          }
507
        break;
508

509
      case EFL_GFX_COLORSPACE_RGB_S3TC_DXT1:
510
      case EFL_GFX_COLORSPACE_RGBA_S3TC_DXT1:
511
      case EFL_GFX_COLORSPACE_RGBA_S3TC_DXT2:
512
      case EFL_GFX_COLORSPACE_RGBA_S3TC_DXT3:
513
      case EFL_GFX_COLORSPACE_RGBA_S3TC_DXT4:
514
      case EFL_GFX_COLORSPACE_RGBA_S3TC_DXT5:
515
         /* FIXME: can convert to ARGB */
516

517
      default:
518
        break;
519
     }
520

521

522
   // fallback to two-pass
523
   if (to_argb && from_argb)
524
     {
525
        if (region_can) *region_can = (reg1 && reg2);
526
        return _convert_generic_two_pass;
527
     }
528

529
   ERR("unsupported colorspace conversion from %d to %d", srccs, dstcs);
530
   if (region_can) *region_can = EINA_FALSE;
531
   return NULL;
532
}
533

534
int
535
efl_draw_argb_premul(uint32_t *data, unsigned int len)
536
{
537
   uint32_t *de = data + len;
538
   int nas = 0;
539

540
#ifdef BUILD_NEON
541
   if (eina_cpu_features_get() & EINA_CPU_NEON)
542
     {
543
        uint8x8_t mask_0x00 = vdup_n_u8(0);
544
        uint8x8_t mask_0x01 = vdup_n_u8(1);
545
        uint8x8_t mask_0xff = vdup_n_u8(255);
546
        uint8x8_t cmp;
547
        uint64x1_t tmp;
548

549
        while (data <= de - 8)
550
          {
551
             uint8x8x4_t rgba = vld4_u8((uint8_t *) data);
552

553
             cmp = vand_u8(vorr_u8(vceq_u8(rgba.val[3], mask_0xff),
554
                                   vceq_u8(rgba.val[3], mask_0x00)),
555
                           mask_0x01);
556
             tmp = vpaddl_u32(vpaddl_u16(vpaddl_u8(cmp)));
557
             nas += vget_lane_u32(vreinterpret_u32_u64(tmp), 0);
558

559
             uint16x8x4_t lrgba;
560
             lrgba.val[0] = vmovl_u8(rgba.val[0]);
561
             lrgba.val[1] = vmovl_u8(rgba.val[1]);
562
             lrgba.val[2] = vmovl_u8(rgba.val[2]);
563
             lrgba.val[3] = vaddl_u8(rgba.val[3], mask_0x01);
564

565
             rgba.val[0] = vshrn_n_u16(vmlaq_u16(lrgba.val[0], lrgba.val[0],
566
                                                 lrgba.val[3]), 8);
567
             rgba.val[1] = vshrn_n_u16(vmlaq_u16(lrgba.val[1], lrgba.val[1],
568
                                                 lrgba.val[3]), 8);
569
             rgba.val[2] = vshrn_n_u16(vmlaq_u16(lrgba.val[2], lrgba.val[2],
570
                                                 lrgba.val[3]), 8);
571
             vst4_u8((uint8_t *) data, rgba);
572
             data += 8;
573
          }
574
     }
575
#endif
576

577
   while (data < de)
578
     {
579
        uint32_t  a = 1 + (*data >> 24);
580

581
        *data = (*data & 0xff000000) +
582
          (((((*data) >> 8) & 0xff) * a) & 0xff00) +
583
          (((((*data) & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
584
        data++;
585

586
        if ((a == 1) || (a == 256))
587
          nas++;
588
     }
589

590
   return nas;
591
}
592

593
void
594
efl_draw_argb_unpremul(uint32_t *data, unsigned int len)
595
{
596
   uint32_t *de = data + len;
597
   uint32_t p_val = 0x00000000, p_res = 0x00000000;
598

599
   while (data < de)
600
     {
601
        uint32_t a = (*data >> 24);
602

603
        if (p_val == *data) *data = p_res;
604
        else
605
          {
606
             p_val = *data;
607
             if ((a > 0) && (a < 255))
608
               *data = DRAW_ARGB_JOIN(a,
609
                                      (R_VAL(data) * 255) / a,
610
                                      (G_VAL(data) * 255) / a,
611
                                      (B_VAL(data) * 255) / a);
612
             else if (a == 0)
613
               *data = 0x00000000;
614
             p_res = *data;
615
          }
616
        data++;
617
     }
618
}
619

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.