hextile.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * noVNC: HTML5 VNC client
  3. * Copyright (C) 2012 Joel Martin
  4. * Copyright (C) 2018 Samuel Mannehed for Cendio AB
  5. * Copyright (C) 2018 Pierre Ossman for Cendio AB
  6. * Licensed under MPL 2.0 (see LICENSE.txt)
  7. *
  8. * See README.md for usage and integration instructions.
  9. *
  10. */
  11. import * as Log from '../util/logging.js';
  12. export default class HextileDecoder {
  13. constructor() {
  14. this._tiles = 0;
  15. this._lastsubencoding = 0;
  16. }
  17. decodeRect(x, y, width, height, sock, display, depth) {
  18. if (this._tiles === 0) {
  19. this._tiles_x = Math.ceil(width / 16);
  20. this._tiles_y = Math.ceil(height / 16);
  21. this._total_tiles = this._tiles_x * this._tiles_y;
  22. this._tiles = this._total_tiles;
  23. }
  24. while (this._tiles > 0) {
  25. let bytes = 1;
  26. if (sock.rQwait("HEXTILE", bytes)) {
  27. return false;
  28. }
  29. let rQ = sock.rQ;
  30. let rQi = sock.rQi;
  31. let subencoding = rQ[rQi]; // Peek
  32. if (subencoding > 30) { // Raw
  33. throw new Error("Illegal hextile subencoding (subencoding: " +
  34. subencoding + ")");
  35. }
  36. const curr_tile = this._total_tiles - this._tiles;
  37. const tile_x = curr_tile % this._tiles_x;
  38. const tile_y = Math.floor(curr_tile / this._tiles_x);
  39. const tx = x + tile_x * 16;
  40. const ty = y + tile_y * 16;
  41. const tw = Math.min(16, (x + width) - tx);
  42. const th = Math.min(16, (y + height) - ty);
  43. // Figure out how much we are expecting
  44. if (subencoding & 0x01) { // Raw
  45. bytes += tw * th * 4;
  46. } else {
  47. if (subencoding & 0x02) { // Background
  48. bytes += 4;
  49. }
  50. if (subencoding & 0x04) { // Foreground
  51. bytes += 4;
  52. }
  53. if (subencoding & 0x08) { // AnySubrects
  54. bytes++; // Since we aren't shifting it off
  55. if (sock.rQwait("HEXTILE", bytes)) {
  56. return false;
  57. }
  58. let subrects = rQ[rQi + bytes - 1]; // Peek
  59. if (subencoding & 0x10) { // SubrectsColoured
  60. bytes += subrects * (4 + 2);
  61. } else {
  62. bytes += subrects * 2;
  63. }
  64. }
  65. }
  66. if (sock.rQwait("HEXTILE", bytes)) {
  67. return false;
  68. }
  69. // We know the encoding and have a whole tile
  70. rQi++;
  71. if (subencoding === 0) {
  72. if (this._lastsubencoding & 0x01) {
  73. // Weird: ignore blanks are RAW
  74. Log.Debug(" Ignoring blank after RAW");
  75. } else {
  76. display.fillRect(tx, ty, tw, th, this._background);
  77. }
  78. } else if (subencoding & 0x01) { // Raw
  79. display.blitImage(tx, ty, tw, th, rQ, rQi);
  80. rQi += bytes - 1;
  81. } else {
  82. if (subencoding & 0x02) { // Background
  83. this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
  84. rQi += 4;
  85. }
  86. if (subencoding & 0x04) { // Foreground
  87. this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
  88. rQi += 4;
  89. }
  90. display.startTile(tx, ty, tw, th, this._background);
  91. if (subencoding & 0x08) { // AnySubrects
  92. let subrects = rQ[rQi];
  93. rQi++;
  94. for (let s = 0; s < subrects; s++) {
  95. let color;
  96. if (subencoding & 0x10) { // SubrectsColoured
  97. color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
  98. rQi += 4;
  99. } else {
  100. color = this._foreground;
  101. }
  102. const xy = rQ[rQi];
  103. rQi++;
  104. const sx = (xy >> 4);
  105. const sy = (xy & 0x0f);
  106. const wh = rQ[rQi];
  107. rQi++;
  108. const sw = (wh >> 4) + 1;
  109. const sh = (wh & 0x0f) + 1;
  110. display.subTile(sx, sy, sw, sh, color);
  111. }
  112. }
  113. display.finishTile();
  114. }
  115. sock.rQi = rQi;
  116. this._lastsubencoding = subencoding;
  117. this._tiles--;
  118. }
  119. return true;
  120. }
  121. }