chromium/third_party/win_virtual_display/driver/Edid.cpp

// Copyright (c) Microsoft Corporation

#include "Edid.h"
#include <cassert>

namespace display::test {
bool EdidTimingEntry::SetMode(unsigned short width,
                              unsigned short height,
                              unsigned short freq) {
  if (width < 256 || width > 2288) {
    return false;
  }
  if (freq < 60 || freq > 123) {
    return false;
  }
  if (height == (width / 16) * 10) {
    aspect_ratio = 0b00;  // 16:10
  } else if (height == (width / 4) * 3) {
    aspect_ratio = 0b01;  // 4:3
  } else if (height == (width / 5) * 4) {
    aspect_ratio = 0b10;  // 5:4
  } else if (height == (width / 16) * 9) {
    aspect_ratio = 0b11;  // 16:9
  } else {
    return false;  // Invalid aspect ratio.
  }
  x_pixels = static_cast<unsigned char>((width / 8) - 31);
  vertical_frequency = static_cast<unsigned char>(freq - 60);
  return true;
}

int EdidTimingEntry::GetWidth() {
  return (x_pixels + 31) * 8;
}

int EdidTimingEntry::GetHeight() {
  switch (aspect_ratio) {
    default:
    case 0b00:
      return (GetWidth() / 16) * 10;  // 16:10 (EDID >= 1.3; 1:1 otherwise).
    case 0b01:
      return (GetWidth() / 4) * 3;  // 4:3
    case 0b10:
      return (GetWidth() / 5) * 4;  // 5:4
    case 0b11:
      return (GetWidth() / 16) * 9;  // 16:9
  }
}

int EdidTimingEntry::GetVerticalFrequency() {
  return vertical_frequency + 60;
}

EdidTimingEntry* Edid::GetTimingEntry(int entry) {
  assert(0 <= entry && entry < 8);
  // Timing entries start at byte 38.
  return reinterpret_cast<EdidTimingEntry*>(edidBlock.data() + 38 +
                                            (entry * sizeof(EdidTimingEntry)));
}

void Edid::SetProductCode(uint16_t code) {
  // Manufacturer product code is bytes 10-11.
  *(reinterpret_cast<uint16_t*>(edidBlock.data() + 10)) = code;
}

void Edid::SetSerialNumber(uint32_t serial) {
  // Serial number is bytes 12-15.
  *(reinterpret_cast<uint32_t*>(edidBlock.data() + 12)) = serial;
}

void Edid::UpdateChecksum() {
  assert(edidBlock.size() == kBlockSize);
  // Sum all bytes except the last.
  int sum = 0;
  for (int i = 0; i < edidBlock.size() - 1; i++) {
    sum += edidBlock.at(i);
  }
  // Set the last byte to make the sum of ALL bytes mod 256 equal 0.
  edidBlock[edidBlock.size() - 1] =
      (sum % 256) == 0 ? 0 : static_cast<unsigned char>(256 - (sum % 256));
  assert((sum + edidBlock[edidBlock.size() - 1]) % 256 == 0);
}

}  // namespace display::test