tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

YuvStamper.cpp (9861B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifdef HAVE_NETINET_IN_H
      6 #  include <netinet/in.h>
      7 #elif defined XP_WIN
      8 #  include <winsock2.h>
      9 #endif
     10 #include <string.h>
     11 
     12 #include "YuvStamper.h"
     13 #include "mozilla/Sprintf.h"
     14 
     15 typedef uint32_t UINT4;  // Needed for r_crc32() call
     16 extern "C" {
     17 #include "r_crc32.h"
     18 }
     19 
     20 namespace mozilla {
     21 
     22 #define ON_5 0x20
     23 #define ON_4 0x10
     24 #define ON_3 0x08
     25 #define ON_2 0x04
     26 #define ON_1 0x02
     27 #define ON_0 0x01
     28 
     29 /*
     30  0, 0, 1, 1, 0, 0,
     31  0, 1, 0, 0, 1, 0,
     32  1, 0, 0, 0, 0, 1,
     33  1, 0, 0, 0, 0, 1,
     34  1, 0, 0, 0, 0, 1,
     35  0, 1, 0, 0, 1, 0,
     36  0, 0, 1, 1, 0, 0
     37 */
     38 static unsigned char DIGIT_0[] = {ON_3 | ON_2, ON_4 | ON_1, ON_5 | ON_0,
     39                                  ON_5 | ON_0, ON_5 | ON_0, ON_4 | ON_1,
     40                                  ON_3 | ON_2};
     41 
     42 /*
     43  0, 0, 0, 1, 0, 0,
     44  0, 0, 0, 1, 0, 0,
     45  0, 0, 0, 1, 0, 0,
     46  0, 0, 0, 1, 0, 0,
     47  0, 0, 0, 1, 0, 0,
     48  0, 0, 0, 1, 0, 0,
     49  0, 0, 0, 1, 0, 0,
     50 */
     51 static unsigned char DIGIT_1[] = {ON_2, ON_2, ON_2, ON_2, ON_2, ON_2, ON_2};
     52 
     53 /*
     54  1, 1, 1, 1, 1, 0,
     55  0, 0, 0, 0, 0, 1,
     56  0, 0, 0, 0, 0, 1,
     57  0, 1, 1, 1, 1, 0,
     58  1, 0, 0, 0, 0, 0,
     59  1, 0, 0, 0, 0, 0,
     60  0, 1, 1, 1, 1, 1,
     61 */
     62 static unsigned char DIGIT_2[] = {
     63    ON_5 | ON_4 | ON_3 | ON_2 | ON_1, ON_0, ON_0,
     64    ON_4 | ON_3 | ON_2 | ON_1,        ON_5, ON_5,
     65    ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
     66 };
     67 
     68 /*
     69  1, 1, 1, 1, 1, 0,
     70  0, 0, 0, 0, 0, 1,
     71  0, 0, 0, 0, 0, 1,
     72  0, 1, 1, 1, 1, 1,
     73  0, 0, 0, 0, 0, 1,
     74  0, 0, 0, 0, 0, 1,
     75  1, 1, 1, 1, 1, 0,
     76 */
     77 static unsigned char DIGIT_3[] = {
     78    ON_5 | ON_4 | ON_3 | ON_2 | ON_1, ON_0, ON_0,
     79    ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_0, ON_0,
     80    ON_5 | ON_4 | ON_3 | ON_2 | ON_1,
     81 };
     82 
     83 /*
     84  0, 1, 0, 0, 0, 1,
     85  0, 1, 0, 0, 0, 1,
     86  0, 1, 0, 0, 0, 1,
     87  0, 1, 1, 1, 1, 1,
     88  0, 0, 0, 0, 0, 1,
     89  0, 0, 0, 0, 0, 1,
     90  0, 0, 0, 0, 0, 1
     91 */
     92 static unsigned char DIGIT_4[] = {
     93    ON_4 | ON_0, ON_4 | ON_0, ON_4 | ON_0, ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
     94    ON_0,        ON_0,        ON_0,
     95 };
     96 
     97 /*
     98  0, 1, 1, 1, 1, 1,
     99  1, 0, 0, 0, 0, 0,
    100  1, 0, 0, 0, 0, 0,
    101  0, 1, 1, 1, 1, 0,
    102  0, 0, 0, 0, 0, 1,
    103  0, 0, 0, 0, 0, 1,
    104  1, 1, 1, 1, 1, 0,
    105 */
    106 static unsigned char DIGIT_5[] = {
    107    ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_5, ON_5,
    108    ON_4 | ON_3 | ON_2 | ON_1,        ON_0, ON_0,
    109    ON_5 | ON_4 | ON_3 | ON_2 | ON_1,
    110 };
    111 
    112 /*
    113  0, 1, 1, 1, 1, 1,
    114  1, 0, 0, 0, 0, 0,
    115  1, 0, 0, 0, 0, 0,
    116  1, 1, 1, 1, 1, 0,
    117  1, 0, 0, 0, 0, 1,
    118  1, 0, 0, 0, 0, 1,
    119  0, 1, 1, 1, 1, 0,
    120 */
    121 static unsigned char DIGIT_6[] = {
    122    ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_5,        ON_5,
    123    ON_4 | ON_3 | ON_2 | ON_1,        ON_5 | ON_0, ON_5 | ON_0,
    124    ON_4 | ON_3 | ON_2 | ON_1,
    125 };
    126 
    127 /*
    128  1, 1, 1, 1, 1, 1,
    129  0, 0, 0, 0, 0, 1,
    130  0, 0, 0, 0, 1, 0,
    131  0, 0, 0, 1, 0, 0,
    132  0, 0, 1, 0, 0, 0,
    133  0, 1, 0, 0, 0, 0,
    134  1, 0, 0, 0, 0, 0
    135 */
    136 static unsigned char DIGIT_7[] = {ON_5 | ON_4 | ON_3 | ON_2 | ON_1 | ON_0,
    137                                  ON_0,
    138                                  ON_1,
    139                                  ON_2,
    140                                  ON_3,
    141                                  ON_4,
    142                                  ON_5};
    143 
    144 /*
    145  0, 1, 1, 1, 1, 1,
    146  1, 0, 0, 0, 0, 1,
    147  1, 0, 0, 0, 0, 1,
    148  0, 1, 1, 1, 1, 0,
    149  1, 0, 0, 0, 0, 1,
    150  1, 0, 0, 0, 0, 1,
    151  0, 1, 1, 1, 1, 0
    152 */
    153 static unsigned char DIGIT_8[] = {
    154    ON_4 | ON_3 | ON_2 | ON_1, ON_5 | ON_0, ON_5 | ON_0,
    155    ON_4 | ON_3 | ON_2 | ON_1, ON_5 | ON_0, ON_5 | ON_0,
    156    ON_4 | ON_3 | ON_2 | ON_1,
    157 };
    158 
    159 /*
    160  0, 1, 1, 1, 1, 1,
    161  1, 0, 0, 0, 0, 1,
    162  1, 0, 0, 0, 0, 1,
    163  0, 1, 1, 1, 1, 1,
    164  0, 0, 0, 0, 0, 1,
    165  0, 0, 0, 0, 0, 1,
    166  0, 1, 1, 1, 1, 0
    167 */
    168 static unsigned char DIGIT_9[] = {
    169    ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_5 | ON_0, ON_5 | ON_0,
    170    ON_4 | ON_3 | ON_2 | ON_1 | ON_0, ON_0,        ON_0,
    171    ON_4 | ON_3 | ON_2 | ON_1,
    172 };
    173 
    174 static unsigned char* DIGITS[] = {DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3, DIGIT_4,
    175                                  DIGIT_5, DIGIT_6, DIGIT_7, DIGIT_8, DIGIT_9};
    176 
    177 YuvStamper::YuvStamper(unsigned char* pYData, uint32_t width, uint32_t height,
    178                       uint32_t stride, uint32_t x, uint32_t y,
    179                       unsigned char symbol_width, unsigned char symbol_height)
    180    : pYData(pYData),
    181      mStride(stride),
    182      mWidth(width),
    183      mHeight(height),
    184      mSymbolWidth(symbol_width),
    185      mSymbolHeight(symbol_height),
    186      mCursor(x, y) {}
    187 
    188 bool YuvStamper::Encode(uint32_t width, uint32_t height, uint32_t stride,
    189                        unsigned char* pYData, unsigned char* pMsg,
    190                        size_t msg_len, uint32_t x, uint32_t y) {
    191  YuvStamper stamper(pYData, width, height, stride, x, y, sBitSize, sBitSize);
    192 
    193  // Reserve space for a checksum.
    194  if (stamper.Capacity() < 8 * (msg_len + sizeof(uint32_t))) {
    195    return false;
    196  }
    197 
    198  bool ok = false;
    199  uint32_t crc;
    200  unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc);
    201  r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &crc);
    202  crc = htonl(crc);
    203 
    204  while (msg_len-- > 0) {
    205    if (!stamper.Write8(*pMsg++)) {
    206      return false;
    207    }
    208  }
    209 
    210  // Add checksum after the message.
    211  ok = stamper.Write8(*pCrc++) && stamper.Write8(*pCrc++) &&
    212       stamper.Write8(*pCrc++) && stamper.Write8(*pCrc++);
    213 
    214  return ok;
    215 }
    216 
    217 bool YuvStamper::Decode(uint32_t width, uint32_t height, uint32_t stride,
    218                        unsigned char* pYData, unsigned char* pMsg,
    219                        size_t msg_len, uint32_t x, uint32_t y) {
    220  YuvStamper stamper(pYData, width, height, stride, x, y, sBitSize, sBitSize);
    221 
    222  unsigned char* ptr = pMsg;
    223  size_t len = msg_len;
    224  uint32_t crc, msg_crc;
    225  unsigned char* pCrc = reinterpret_cast<unsigned char*>(&crc);
    226 
    227  // Account for space reserved for the checksum
    228  if (stamper.Capacity() < 8 * (len + sizeof(uint32_t))) {
    229    return false;
    230  }
    231 
    232  while (len-- > 0) {
    233    if (!stamper.Read8(*ptr++)) {
    234      return false;
    235    }
    236  }
    237 
    238  if (!(stamper.Read8(*pCrc++) && stamper.Read8(*pCrc++) &&
    239        stamper.Read8(*pCrc++) && stamper.Read8(*pCrc++))) {
    240    return false;
    241  }
    242 
    243  r_crc32(reinterpret_cast<char*>(pMsg), (int)msg_len, &msg_crc);
    244  return crc == htonl(msg_crc);
    245 }
    246 
    247 inline uint32_t YuvStamper::Capacity() {
    248  // Enforce at least a symbol width and height offset from outer edges.
    249  if (mCursor.y + mSymbolHeight > mHeight) {
    250    return 0;
    251  }
    252 
    253  if (mCursor.x + mSymbolWidth > mWidth && !AdvanceCursor()) {
    254    return 0;
    255  }
    256 
    257  // Normalize frame integral to mSymbolWidth x mSymbolHeight
    258  uint32_t width = mWidth / mSymbolWidth;
    259  uint32_t height = mHeight / mSymbolHeight;
    260  uint32_t x = mCursor.x / mSymbolWidth;
    261  uint32_t y = mCursor.y / mSymbolHeight;
    262 
    263  return (width * height - width * y) - x;
    264 }
    265 
    266 bool YuvStamper::Write8(unsigned char value) {
    267  // Encode MSB to LSB.
    268  unsigned char mask = 0x80;
    269  while (mask) {
    270    if (!WriteBit(!!(value & mask))) {
    271      return false;
    272    }
    273    mask >>= 1;
    274  }
    275  return true;
    276 }
    277 
    278 bool YuvStamper::WriteBit(bool one) {
    279  // A bit is mapped to a mSymbolWidth x mSymbolHeight square of luma data
    280  // points. Don't use ternary op.:
    281  // https://bugzilla.mozilla.org/show_bug.cgi?id=1001708
    282  unsigned char value;
    283  if (one)
    284    value = sYOn;
    285  else
    286    value = sYOff;
    287 
    288  for (uint32_t y = 0; y < mSymbolHeight; y++) {
    289    for (uint32_t x = 0; x < mSymbolWidth; x++) {
    290      *(pYData + (mCursor.x + x) + ((mCursor.y + y) * mStride)) = value;
    291    }
    292  }
    293 
    294  return AdvanceCursor();
    295 }
    296 
    297 bool YuvStamper::AdvanceCursor() {
    298  mCursor.x += mSymbolWidth;
    299  if (mCursor.x + mSymbolWidth > mWidth) {
    300    // move to the start of the next row if possible.
    301    mCursor.y += mSymbolHeight;
    302    if (mCursor.y + mSymbolHeight > mHeight) {
    303      // end of frame, do not advance
    304      mCursor.y -= mSymbolHeight;
    305      mCursor.x -= mSymbolWidth;
    306      return false;
    307    } else {
    308      mCursor.x = 0;
    309    }
    310  }
    311 
    312  return true;
    313 }
    314 
    315 bool YuvStamper::Read8(unsigned char& value) {
    316  unsigned char octet = 0;
    317  unsigned char bit = 0;
    318 
    319  for (int i = 8; i > 0; --i) {
    320    if (!ReadBit(bit)) {
    321      return false;
    322    }
    323    octet <<= 1;
    324    octet |= bit;
    325  }
    326 
    327  value = octet;
    328  return true;
    329 }
    330 
    331 bool YuvStamper::ReadBit(unsigned char& bit) {
    332  uint32_t sum = 0;
    333  for (uint32_t y = 0; y < mSymbolHeight; y++) {
    334    for (uint32_t x = 0; x < mSymbolWidth; x++) {
    335      sum += *(pYData + mStride * (mCursor.y + y) + mCursor.x + x);
    336    }
    337  }
    338 
    339  // apply threshold to collected bit square
    340  bit = (sum > (sBitThreshold * mSymbolWidth * mSymbolHeight)) ? 1 : 0;
    341  return AdvanceCursor();
    342 }
    343 
    344 bool YuvStamper::WriteDigits(uint32_t value) {
    345  char buf[20];
    346  SprintfLiteral(buf, "%.5u", value);
    347  size_t size = strlen(buf);
    348 
    349  if (Capacity() < size) {
    350    return false;
    351  }
    352 
    353  for (size_t i = 0; i < size; ++i) {
    354    if (!WriteDigit(buf[i] - '0')) return false;
    355    if (!AdvanceCursor()) {
    356      return false;
    357    }
    358  }
    359 
    360  return true;
    361 }
    362 
    363 bool YuvStamper::WriteDigit(unsigned char digit) {
    364  if (digit > sizeof(DIGITS) / sizeof(DIGITS[0])) return false;
    365 
    366  unsigned char* dig = DIGITS[digit];
    367  for (uint32_t row = 0; row < sDigitHeight; ++row) {
    368    unsigned char mask = 0x01 << (sDigitWidth - 1);
    369    for (uint32_t col = 0; col < sDigitWidth; ++col, mask >>= 1) {
    370      if (dig[row] & mask) {
    371        for (uint32_t xx = 0; xx < sPixelSize; ++xx) {
    372          for (uint32_t yy = 0; yy < sPixelSize; ++yy) {
    373            WritePixel(pYData, mCursor.x + (col * sPixelSize) + xx,
    374                       mCursor.y + (row * sPixelSize) + yy);
    375          }
    376        }
    377      }
    378    }
    379  }
    380 
    381  return true;
    382 }
    383 
    384 void YuvStamper::WritePixel(unsigned char* data, uint32_t x, uint32_t y) {
    385  unsigned char* ptr = &data[y * mStride + x];
    386  // Don't use ternary op.: https://bugzilla.mozilla.org/show_bug.cgi?id=1001708
    387  if (*ptr > sLumaThreshold)
    388    *ptr = sLumaMin;
    389  else
    390    *ptr = sLumaMax;
    391 }
    392 
    393 }  // namespace mozilla.