Пример #1
0
already_AddRefed<DrawTarget>
nsShmImage::CreateDrawTarget(const mozilla::LayoutDeviceIntRegion& aRegion)
{
  // Wait for any in-flight requests to complete.
  // Typically X clients would wait for a XShmCompletionEvent to be received,
  // but this works as it's sent immediately after the request is processed.
  xcb_generic_error_t* error;
  if (mLastRequest.sequence != XCB_NONE &&
      (error = xcb_request_check(mConnection, mLastRequest)))
  {
    gShmAvailable = false;
    free(error);
    return nullptr;
  }

  // Due to bug 1205045, we must avoid making GTK calls off the main thread to query window size.
  // Instead we just track the largest offset within the image we are drawing to and grow the image
  // to accomodate it. Since usually the entire window is invalidated on the first paint to it,
  // this should grow the image to the necessary size quickly without many intermediate reallocations.
  IntRect bounds = aRegion.GetBounds().ToUnknownRect();
  IntSize size(bounds.XMost(), bounds.YMost());
  if (size.width > mSize.width || size.height > mSize.height) {
    DestroyImage();
    if (!CreateImage(size)) {
      return nullptr;
    }
  }

  return gfxPlatform::GetPlatform()->CreateDrawTargetForData(
    reinterpret_cast<unsigned char*>(mShmAddr)
      + BytesPerPixel(mFormat) * (bounds.y * mSize.width + bounds.x),
    bounds.Size(),
    BytesPerPixel(mFormat) * mSize.width,
    mFormat);
}
Пример #2
0
void
DrawEventRecorderMemory::FlushItem(IntRect aRect)
{
  MOZ_RELEASE_ASSERT(!aRect.IsEmpty());
  // Detaching our existing resources will add some
  // destruction events to our stream so we need to do that
  // first.
  DetachResources();

  // See moz2d_renderer.rs for a description of the stream format
  WriteElement(mIndex, mOutputStream.mLength);

  // write out the fonts into the extra data section
  mSerializeCallback(mOutputStream, mScaledFonts);
  WriteElement(mIndex, mOutputStream.mLength);

  WriteElement(mIndex, aRect.x);
  WriteElement(mIndex, aRect.y);
  WriteElement(mIndex, aRect.XMost());
  WriteElement(mIndex, aRect.YMost());
  ClearResources();

  // write out a new header for the next recording in the stream
  WriteHeader(mOutputStream);
}
Пример #3
0
already_AddRefed<CompositingRenderTarget>
BasicCompositor::CreateRenderTargetForWindow(const IntRect& aRect, SurfaceInitMode aInit, BufferMode aBufferMode)
{
  if (aBufferMode != BufferMode::BUFFER_NONE) {
    return CreateRenderTarget(aRect, aInit);
  }

  MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");

  if (aRect.width * aRect.height == 0) {
    return nullptr;
  }

  MOZ_ASSERT(mDrawTarget);

  // Adjust bounds rect to account for new origin at (0, 0).
  IntRect rect(0, 0, aRect.XMost(), aRect.YMost());
  RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(mDrawTarget, rect);

  if (aInit == INIT_MODE_CLEAR) {
    mDrawTarget->ClearRect(gfx::Rect(aRect));
  }

  return rt.forget();
}
Пример #4
0
void
CheckGeneratedImage(Decoder* aDecoder,
                    const IntRect& aRect,
                    uint8_t aFuzz /* = 0 */)
{
  RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
  RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
  const IntSize surfaceSize = surface->GetSize();

  // This diagram shows how the surface is divided into regions that the code
  // below tests for the correct content. The output rect is the bounds of the
  // region labeled 'C'.
  //
  // +---------------------------+
  // |             A             |
  // +---------+--------+--------+
  // |    B    |   C    |   D    |
  // +---------+--------+--------+
  // |             E             |
  // +---------------------------+

  // Check that the output rect itself is green. (Region 'C'.)
  EXPECT_TRUE(RectIsSolidColor(surface, aRect, BGRAColor::Green(), aFuzz));

  // Check that the area above the output rect is transparent. (Region 'A'.)
  EXPECT_TRUE(RectIsSolidColor(surface,
                               IntRect(0, 0, surfaceSize.width, aRect.y),
                               BGRAColor::Transparent(), aFuzz));

  // Check that the area to the left of the output rect is transparent. (Region 'B'.)
  EXPECT_TRUE(RectIsSolidColor(surface,
                               IntRect(0, aRect.y, aRect.x, aRect.YMost()),
                               BGRAColor::Transparent(), aFuzz));

  // Check that the area to the right of the output rect is transparent. (Region 'D'.)
  const int32_t widthOnRight = surfaceSize.width - aRect.XMost();
  EXPECT_TRUE(RectIsSolidColor(surface,
                               IntRect(aRect.XMost(), aRect.y, widthOnRight, aRect.YMost()),
                               BGRAColor::Transparent(), aFuzz));

  // Check that the area below the output rect is transparent. (Region 'E'.)
  const int32_t heightBelow = surfaceSize.height - aRect.YMost();
  EXPECT_TRUE(RectIsSolidColor(surface,
                               IntRect(0, aRect.YMost(), surfaceSize.width, heightBelow),
                               BGRAColor::Transparent(), aFuzz));
}
Пример #5
0
void
CheckGeneratedPalettedImage(Decoder* aDecoder, const IntRect& aRect)
{
  RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
  IntSize imageSize = currentFrame->GetImageSize();

  // This diagram shows how the surface is divided into regions that the code
  // below tests for the correct content. The output rect is the bounds of the
  // region labeled 'C'.
  //
  // +---------------------------+
  // |             A             |
  // +---------+--------+--------+
  // |    B    |   C    |   D    |
  // +---------+--------+--------+
  // |             E             |
  // +---------------------------+

  // Check that the output rect itself is all 255's. (Region 'C'.)
  EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder, aRect, 255));

  // Check that the area above the output rect is all 0's. (Region 'A'.)
  EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
                                       IntRect(0, 0, imageSize.width, aRect.y),
                                       0));

  // Check that the area to the left of the output rect is all 0's. (Region 'B'.)
  EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
                                       IntRect(0, aRect.y, aRect.x, aRect.YMost()),
                                       0));

  // Check that the area to the right of the output rect is all 0's. (Region 'D'.)
  const int32_t widthOnRight = imageSize.width - aRect.XMost();
  EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
                                       IntRect(aRect.XMost(), aRect.y, widthOnRight, aRect.YMost()),
                                       0));

  // Check that the area below the output rect is transparent. (Region 'E'.)
  const int32_t heightBelow = imageSize.height - aRect.YMost();
  EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
                                       IntRect(0, aRect.YMost(), imageSize.width, heightBelow),
                                       0));
}
Пример #6
0
void
FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntRect &aValue)
{
  if (mType == FilterType::TURBULENCE) {
    MOZ_ASSERT(aIndex == ATT_TURBULENCE_RECT);

    mEffect->SetValue(D2D1_TURBULENCE_PROP_OFFSET, D2D1::Vector2F(Float(aValue.X()), Float(aValue.Y())));
    mEffect->SetValue(D2D1_TURBULENCE_PROP_SIZE, D2D1::Vector2F(Float(aValue.Width()), Float(aValue.Height())));
    return;
  }

  UINT32 input = GetD2D1PropForAttribute(mType, aIndex);
  MOZ_ASSERT(input < mEffect->GetPropertyCount());

  mEffect->SetValue(input, D2D1::RectF(Float(aValue.X()), Float(aValue.Y()),
                                       Float(aValue.XMost()), Float(aValue.YMost())));
}
Пример #7
0
bool
RectIsSolidColor(SourceSurface* aSurface,
                 const IntRect& aRect,
                 BGRAColor aColor,
                 uint8_t aFuzz /* = 0 */)
{
  IntSize surfaceSize = aSurface->GetSize();
  IntRect rect =
    aRect.Intersect(IntRect(0, 0, surfaceSize.width, surfaceSize.height));

  RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
  ASSERT_TRUE_OR_RETURN(dataSurface != nullptr, false);

  ASSERT_EQ_OR_RETURN(dataSurface->Stride(), surfaceSize.width * 4, false);

  DataSourceSurface::ScopedMap mapping(dataSurface,
                                       DataSourceSurface::MapType::READ);
  ASSERT_TRUE_OR_RETURN(mapping.IsMapped(), false);

  uint8_t* data = dataSurface->GetData();
  ASSERT_TRUE_OR_RETURN(data != nullptr, false);

  int32_t rowLength = dataSurface->Stride();
  for (int32_t row = rect.y; row < rect.YMost(); ++row) {
    for (int32_t col = rect.x; col < rect.XMost(); ++col) {
      int32_t i = row * rowLength + col * 4;
      if (aFuzz != 0) {
        ASSERT_LE_OR_RETURN(abs(aColor.mBlue - data[i + 0]), aFuzz, false);
        ASSERT_LE_OR_RETURN(abs(aColor.mGreen - data[i + 1]), aFuzz, false);
        ASSERT_LE_OR_RETURN(abs(aColor.mRed - data[i + 2]), aFuzz, false);
        ASSERT_LE_OR_RETURN(abs(aColor.mAlpha - data[i + 3]), aFuzz, false);
      } else {
        ASSERT_EQ_OR_RETURN(aColor.mBlue,  data[i + 0], false);
        ASSERT_EQ_OR_RETURN(aColor.mGreen, data[i + 1], false);
        ASSERT_EQ_OR_RETURN(aColor.mRed,   data[i + 2], false);
        ASSERT_EQ_OR_RETURN(aColor.mAlpha, data[i + 3], false);
      }
    }
  }

  return true;
}
Пример #8
0
void
DrawTargetD2D1::CopySurface(SourceSurface *aSurface,
                            const IntRect &aSourceRect,
                            const IntPoint &aDestination)
{
  MarkChanged();

  mDC->SetTransform(D2D1::IdentityMatrix());
  mTransformDirty = true;

  Matrix mat;
  RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP);

  if (!mat.IsIdentity()) {
    gfxDebug() << *this << ": At this point complex partial uploads are not supported for CopySurface.";
    return;
  }

  mDC->DrawImage(image, D2D1::Point2F(Float(aDestination.x), Float(aDestination.y)),
                 D2D1::RectF(Float(aSourceRect.x), Float(aSourceRect.y), 
                             Float(aSourceRect.XMost()), Float(aSourceRect.YMost())),
                 D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
}
Пример #9
0
bool
PalettedRectIsSolidColor(Decoder* aDecoder, const IntRect& aRect, uint8_t aColor)
{
  RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
  uint8_t* imageData;
  uint32_t imageLength;
  currentFrame->GetImageData(&imageData, &imageLength);
  ASSERT_TRUE_OR_RETURN(imageData, false);

  // Clamp to the frame rect. If any pixels outside the frame rect are included,
  // we immediately fail, because such pixels don't have any "color" in the
  // sense this function measures - they're transparent, and that doesn't
  // necessarily correspond to any color palette index at all.
  IntRect frameRect = currentFrame->GetRect();
  ASSERT_EQ_OR_RETURN(imageLength, uint32_t(frameRect.Area()), false);
  IntRect rect = aRect.Intersect(frameRect);
  ASSERT_EQ_OR_RETURN(rect.Area(), aRect.Area(), false);

  // Translate |rect| by |frameRect.TopLeft()| to reflect the fact that the
  // frame rect's offset doesn't actually mean anything in terms of the
  // in-memory representation of the surface. The image data starts at the upper
  // left corner of the frame rect, in other words.
  rect -= frameRect.TopLeft();

  // Walk through the image data and make sure that the entire rect has the
  // palette index |aColor|.
  int32_t rowLength = frameRect.width;
  for (int32_t row = rect.y; row < rect.YMost(); ++row) {
    for (int32_t col = rect.x; col < rect.XMost(); ++col) {
      int32_t i = row * rowLength + col;
      ASSERT_EQ_OR_RETURN(aColor, imageData[i], false);
    }
  }

  return true;
}
Пример #10
0
void
DeprecatedTextureHostSystemMemD3D9::UpdateImpl(const SurfaceDescriptor& aImage,
                                     nsIntRegion *aRegion,
                                     nsIntPoint *aOffset)
{
  MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TSurfaceDescriptorD3D9);
  MOZ_ASSERT(mCompositor, "Must have compositor to update.");

  if (!mCompositor->device()) {
    return;
  }

  IDirect3DTexture9* texture =
    reinterpret_cast<IDirect3DTexture9*>(aImage.get_SurfaceDescriptorD3D9().texture());

  if (!texture) {
    Reset();
    return;
  }

  D3DSURFACE_DESC desc;
  texture->GetLevelDesc(0, &desc);
  HRESULT hr = texture->GetLevelDesc(0, &desc);
  if (FAILED(hr)) {
    Reset();
    return;
  }

  mSize.width = desc.Width;
  mSize.height = desc.Height;

  _D3DFORMAT format = desc.Format;
  uint32_t bpp = 0;
  switch (format) {
  case D3DFMT_X8R8G8B8:
    mFormat = SurfaceFormat::B8G8R8X8;
    bpp = 4;
    break;
  case D3DFMT_A8R8G8B8:
    mFormat = SurfaceFormat::B8G8R8A8;
    bpp = 4;
    break;
  case D3DFMT_A8:
    mFormat = SurfaceFormat::A8;
    bpp = 1;
    break;
  default:
    NS_ERROR("Bad image format");
  }

  int32_t maxSize = mCompositor->GetMaxTextureSize();
  if (mSize.width <= maxSize && mSize.height <= maxSize) {
    mIsTiled = false;

    mTexture = TextureToTexture(gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(),
                                texture, mSize, format);
    if (!mTexture) {
      NS_WARNING("Could not upload texture");
      Reset();
      return;
    }
  } else {
    mIsTiled = true;

    uint32_t tileCount = GetRequiredTilesD3D9(mSize.width, maxSize) *
                         GetRequiredTilesD3D9(mSize.height, maxSize);
    mTileTextures.resize(tileCount);

    for (uint32_t i = 0; i < tileCount; i++) {
      IntRect tileRect = GetTileRect(i);
      RECT d3dTileRect;
      d3dTileRect.left = tileRect.x;
      d3dTileRect.top = tileRect.y;
      d3dTileRect.right = tileRect.XMost();
      d3dTileRect.bottom = tileRect.YMost();
      D3DLOCKED_RECT lockedRect;
      texture->LockRect(0, &lockedRect, &d3dTileRect, 0);
      mTileTextures[i] = DataToTexture(gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(),
                                       reinterpret_cast<unsigned char*>(lockedRect.pBits),
                                       lockedRect.Pitch,
                                       tileRect.Size(),
                                       format,
                                       bpp);
      texture->UnlockRect(0);
      if (!mTileTextures[i]) {
        NS_WARNING("Could not upload texture");
        Reset();
        return;
      }
    }
  }
}
Пример #11
0
static void
BoxBlur(uint8_t* aData,
        const int32_t aLobes[3][2],
        int32_t aWidth,
        int32_t aRows,
        int32_t aStride,
        IntRect aSkipRect)
{
  if (aTranspose) {
    swap(aWidth, aRows);
    swap(aSkipRect.x, aSkipRect.y);
    swap(aSkipRect.width, aSkipRect.height);
  }

  MOZ_ASSERT(aWidth > 0);

  // All three passes of the box blur that approximate the Gaussian are done
  // on each row in turn, so we only need two temporary row buffers to process
  // each row, instead of a full-sized buffer. Data moves from the source to the
  // first temporary, from the first temporary to the second, then from the second
  // back to the destination. This way is more cache-friendly than processing whe
  // whole buffer in each pass and thus yields a nice speedup.
  uint8_t* tmpRow = new (std::nothrow) uint8_t[2 * aWidth];
  if (!tmpRow) {
    return;
  }
  uint8_t* tmpRow2 = tmpRow + aWidth;

  const int32_t stride = aTranspose ? 1 : aStride;
  bool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
                                aWidth <= aSkipRect.XMost();

  for (int32_t y = 0; y < aRows; y++) {
    // Check whether the skip rect intersects this row. If the skip
    // rect covers the whole surface in this row, we can avoid
    // this row entirely (and any others along the skip rect).
    bool inSkipRectY = y >= aSkipRect.y &&
                       y < aSkipRect.YMost();
    if (inSkipRectY && skipRectCoversWholeRow) {
      aData += stride * (aSkipRect.YMost() - y);
      y = aSkipRect.YMost() - 1;
      continue;
    }

    // Read in data from the source transposed if necessary.
    BoxBlurRow<aTranspose, false>(aData, tmpRow, aLobes[0][0], aLobes[0][1], aWidth, aStride, 0, aWidth);

    // For the middle pass, the data is already pre-transposed and does not need to be post-transposed yet.
    BoxBlurRow<false, false>(tmpRow, tmpRow2, aLobes[1][0], aLobes[1][1], aWidth, aStride, 0, aWidth);

    // Write back data to the destination transposed if necessary too.
    // Make sure not to overwrite the skip rect by only outputting to the
    // destination before and after the skip rect, if requested.
    int32_t skipStart = inSkipRectY ? min(max(aSkipRect.x, 0), aWidth) : aWidth;
    int32_t skipEnd = max(skipStart, aSkipRect.XMost());
    if (skipStart > 0) {
      BoxBlurRow<false, aTranspose>(tmpRow2, aData, aLobes[2][0], aLobes[2][1], aWidth, aStride, 0, skipStart);
    }
    if (skipEnd < aWidth) {
      BoxBlurRow<false, aTranspose>(tmpRow2, aData, aLobes[2][0], aLobes[2][1], aWidth, aStride, skipEnd, aWidth);
    }

    aData += stride;
  }

  delete[] tmpRow;
}
Пример #12
0
// |aTexCoordRect| is the rectangle from the texture that we want to
// draw using the given program.  The program already has a necessary
// offset and scale, so the geometry that needs to be drawn is a unit
// square from 0,0 to 1,1.
//
// |aTexSize| is the actual size of the texture, as it can be larger
// than the rectangle given by |aTexCoordRect|.
void
CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                              const Rect& aTexCoordRect,
                                              TextureSource *aTexture)
{
  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
  GLuint vertAttribIndex =
    aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
  GLuint texCoordAttribIndex =
    aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
  NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?");

  // Given what we know about these textures and coordinates, we can
  // compute fmod(t, 1.0f) to get the same texture coordinate out.  If
  // the texCoordRect dimension is < 0 or > width/height, then we have
  // wraparound that we need to deal with by drawing multiple quads,
  // because we can't rely on full non-power-of-two texture support
  // (which is required for the REPEAT wrap mode).

  GLContext::RectTriangles rects;

  GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();

  IntSize realTexSize = aTexture->GetSize();
  if (!mGLContext->CanUploadNonPowerOfTwo()) {
    realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
                          NextPowerOfTwo(realTexSize.height));
  }

  // We need to convert back to actual texels here to get proper behaviour with
  // our GL helper functions. Should fix this sometime.
  // I want to vomit.
  IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
                                 NS_roundf(aTexCoordRect.y * aTexture->GetSize().height),
                                 NS_roundf(aTexCoordRect.width * aTexture->GetSize().width),
                                 NS_roundf(aTexCoordRect.height * aTexture->GetSize().height));

  // This is fairly disgusting - if the texture should be flipped it will have a
  // negative height, in which case we un-invert the texture coords and pass the
  // flipped 'flag' to the functions below. We can't just use the inverted coords
  // because our GL funtions use an explicit flag.
  bool flipped = false;
  if (texCoordRect.height < 0) {
    flipped = true;
    texCoordRect.y = texCoordRect.YMost();
    texCoordRect.height = -texCoordRect.height;
  }

  if (wrapMode == LOCAL_GL_REPEAT) {
    rects.addRect(/* dest rectangle */
                  0.0f, 0.0f, 1.0f, 1.0f,
                  /* tex coords */
                  texCoordRect.x / GLfloat(realTexSize.width),
                  texCoordRect.y / GLfloat(realTexSize.height),
                  texCoordRect.XMost() / GLfloat(realTexSize.width),
                  texCoordRect.YMost() / GLfloat(realTexSize.height),
                  flipped);
  } else {
    nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
                     texCoordRect.width, texCoordRect.height);
    GLContext::DecomposeIntoNoRepeatTriangles(tcRect,
                                              nsIntSize(realTexSize.width, realTexSize.height),
                                              rects, flipped);
  }

  DrawWithVertexBuffer2(mGLContext, mVBOs,
                        LOCAL_GL_TRIANGLES, rects.elements(),
                        vertAttribIndex, rects.vertexPointer(),
                        texCoordAttribIndex, rects.texCoordPointer());
}