示例#1
0
// Computes the area in which aRect1 and aRect2 overlap and fills 'this' with
// the result. Returns FALSE if the rectangles don't intersect.
PRBool nsIntRect::IntersectRect(const nsIntRect &aRect1, const nsIntRect &aRect2)
{
  PRInt32  xmost1 = aRect1.XMost();
  PRInt32  ymost1 = aRect1.YMost();
  PRInt32  xmost2 = aRect2.XMost();
  PRInt32  ymost2 = aRect2.YMost();
  PRInt32  temp;

  x = PR_MAX(aRect1.x, aRect2.x);
  y = PR_MAX(aRect1.y, aRect2.y);

  // Compute the destination width
  temp = PR_MIN(xmost1, xmost2);
  if (temp <= x) {
    Empty();
    return PR_FALSE;
  }
  width = temp - x;

  // Compute the destination height
  temp = PR_MIN(ymost1, ymost2);
  if (temp <= y) {
    Empty();
    return PR_FALSE;
  }
  height = temp - y;

  return PR_TRUE;
}
示例#2
0
/**
 * Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
 * left and right.
 * XXX shouldn't we pass stride in separately here?
 */
static void
BoxBlurVertical(unsigned char* aInput,
                unsigned char* aOutput,
                PRInt32 aTopLobe,
                PRInt32 aBottomLobe,
                PRInt32 aWidth,
                PRInt32 aRows,
                const nsIntRect& aSkipRect)
{
    NS_ASSERTION(aRows > 0, "Can't handle zero rows here");

    PRInt32 boxSize = aTopLobe + aBottomLobe + 1;
    PRBool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
                                       aRows <= aSkipRect.YMost();

    for (PRInt32 x = 0; x < aWidth; x++) {
        PRBool inSkipRectX = x >= aSkipRect.x &&
                             x < aSkipRect.XMost();
        if (inSkipRectX && skipRectCoversWholeColumn) {
            x = aSkipRect.XMost() - 1;
            continue;
        }

        PRInt32 alphaSum = 0;
        for (PRInt32 i = 0; i < boxSize; i++) {
            PRInt32 pos = i - aTopLobe;
            // See assertion above; if aRows is zero, then we would have no
            // valid position to clamp to.
            pos = NS_MAX(pos, 0);
            pos = NS_MIN(pos, aRows - 1);
            alphaSum += aInput[aWidth * pos + x];
        }
        for (PRInt32 y = 0; y < aRows; y++) {
            if (inSkipRectX && y >= aSkipRect.y &&
                y < aSkipRect.YMost()) {
                y = aSkipRect.YMost();
                if (y >= aRows)
                    break;

                alphaSum = 0;
                for (PRInt32 i = 0; i < boxSize; i++) {
                    PRInt32 pos = y + i - aTopLobe;
                    // See assertion above; if aRows is zero, then we would have no
                    // valid position to clamp to.
                    pos = NS_MAX(pos, 0);
                    pos = NS_MIN(pos, aRows - 1);
                    alphaSum += aInput[aWidth * pos + x];
                }
            }
            PRInt32 tmp = y - aTopLobe;
            PRInt32 last = NS_MAX(tmp, 0);
            PRInt32 next = NS_MIN(tmp + boxSize, aRows - 1);

            aOutput[aWidth * y + x] = alphaSum/boxSize;

            alphaSum += aInput[aWidth * next + x] -
                        aInput[aWidth * last + x];
        }
    }
}
示例#3
0
// Computes the smallest rectangle that contains both aRect1 and aRect2 and
// fills 'this' with the result. Returns FALSE if both aRect1 and aRect2 are
// empty and TRUE otherwise
PRBool nsIntRect::UnionRect(const nsIntRect &aRect1, const nsIntRect &aRect2)
{
  PRBool  result = PR_TRUE;

  // Is aRect1 empty?
  if (aRect1.IsEmpty()) {
    if (aRect2.IsEmpty()) {
      // Both rectangles are empty which is an error
      Empty();
      result = PR_FALSE;
    } else {
      // aRect1 is empty so set the result to aRect2
      *this = aRect2;
    }
  } else if (aRect2.IsEmpty()) {
    // aRect2 is empty so set the result to aRect1
    *this = aRect1;
  } else {
    PRInt32 xmost1 = aRect1.XMost();
    PRInt32 xmost2 = aRect2.XMost();
    PRInt32 ymost1 = aRect1.YMost();
    PRInt32 ymost2 = aRect2.YMost();

    // Compute the origin
    x = PR_MIN(aRect1.x, aRect2.x);
    y = PR_MIN(aRect1.y, aRect2.y);

    // Compute the size
    width = PR_MAX(xmost1, xmost2) - x;
    height = PR_MAX(ymost1, ymost2) - y;
  }

  return result;
}
示例#4
0
/**
 * Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
 * left and right.
 * XXX shouldn't we pass stride in separately here?
 */
static void
BoxBlurVertical(unsigned char* aInput,
                unsigned char* aOutput,
                PRInt32 aTopLobe,
                PRInt32 aBottomLobe,
                PRInt32 aWidth,
                PRInt32 aRows,
                const nsIntRect& aSkipRect)
{
    PRInt32 boxSize = aTopLobe + aBottomLobe + 1;
    PRBool skipRectCoversWholeColumn = 0 >= aSkipRect.y &&
                                       aRows <= aSkipRect.YMost();

    for (PRInt32 x = 0; x < aWidth; x++) {
        PRBool inSkipRectX = x >= aSkipRect.x &&
                             x < aSkipRect.XMost();
        if (inSkipRectX && skipRectCoversWholeColumn) {
            x = aSkipRect.XMost() - 1;
            continue;
        }

        PRInt32 alphaSum = 0;
        for (PRInt32 i = 0; i < boxSize; i++) {
            PRInt32 pos = i - aTopLobe;
            pos = NS_MAX(pos, 0);
            pos = NS_MIN(pos, aRows - 1);
            alphaSum += aInput[aWidth * pos + x];
        }
        for (PRInt32 y = 0; y < aRows; y++) {
            if (inSkipRectX && y >= aSkipRect.y &&
                y < aSkipRect.YMost()) {
                y = aSkipRect.YMost();
                if (y >= aRows)
                    break;

                alphaSum = 0;
                for (PRInt32 i = 0; i < boxSize; i++) {
                    PRInt32 pos = y + i - aTopLobe;
                    pos = NS_MAX(pos, 0);
                    pos = NS_MIN(pos, aRows - 1);
                    alphaSum += aInput[aWidth * pos + x];
                }
            }
            PRInt32 tmp = y - aTopLobe;
            PRInt32 last = NS_MAX(tmp, 0);
            PRInt32 next = NS_MIN(tmp + boxSize, aRows - 1);

            aOutput[aWidth * y + x] = alphaSum/boxSize;

            alphaSum += aInput[aWidth * next + x] -
                        aInput[aWidth * last + x];
        }
    }
}
示例#5
0
static void
ComputesRGBLuminanceMask(uint8_t *aData,
                         int32_t aStride,
                         const nsIntRect &aRect,
                         float aOpacity)
{
    for (int32_t y = aRect.y; y < aRect.YMost(); y++) {
        for (int32_t x = aRect.x; x < aRect.XMost(); x++) {
            uint8_t *pixel = aData + aStride * y + 4 * x;
            uint8_t a = pixel[GFX_ARGB32_OFFSET_A];

            uint8_t luminance;
            if (a) {
                /* sRGB -> intensity (unpremultiply cancels out the
                 * (a/255.0) multiplication with aOpacity */
                luminance =
                    static_cast<uint8_t>
                    ((pixel[GFX_ARGB32_OFFSET_R] * 0.2125 +
                      pixel[GFX_ARGB32_OFFSET_G] * 0.7154 +
                      pixel[GFX_ARGB32_OFFSET_B] * 0.0721) *
                     aOpacity);
            } else {
                luminance = 0;
            }
            memset(pixel, luminance, 4);
        }
    }
}
示例#6
0
void
nsSVGUtils::UnPremultiplyImageDataAlpha(PRUint8 *data, 
                                        PRInt32 stride,
                                        const nsIntRect &rect)
{
  for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
    for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
      PRUint8 *pixel = data + stride * y + 4 * x;

      PRUint8 a = pixel[GFX_ARGB32_OFFSET_A];
      if (a == 255)
        continue;

      if (a) {
        pixel[GFX_ARGB32_OFFSET_B] = (255 * pixel[GFX_ARGB32_OFFSET_B]) / a;
        pixel[GFX_ARGB32_OFFSET_G] = (255 * pixel[GFX_ARGB32_OFFSET_G]) / a;
        pixel[GFX_ARGB32_OFFSET_R] = (255 * pixel[GFX_ARGB32_OFFSET_R]) / a;
      } else {
        pixel[GFX_ARGB32_OFFSET_B] = 0;
        pixel[GFX_ARGB32_OFFSET_G] = 0;
        pixel[GFX_ARGB32_OFFSET_R] = 0;
      }
    }
  }
}
void
SVGFEGaussianBlurElement::GaussianBlur(const Image* aSource,
                                       const Image* aTarget,
                                       const nsIntRect& aDataRect,
                                       uint32_t aDX, uint32_t aDY)
{
  NS_ASSERTION(nsIntRect(0, 0, aTarget->mImage->Width(), aTarget->mImage->Height()).Contains(aDataRect),
               "aDataRect out of bounds");

  nsAutoArrayPtr<uint8_t> tmp(new uint8_t[aTarget->mImage->GetDataSize()]);
  if (!tmp)
    return;
  memset(tmp, 0, aTarget->mImage->GetDataSize());

  bool alphaOnly = AreAllColorChannelsZero(aTarget);

  const uint8_t* sourceData = aSource->mImage->Data();
  uint8_t* targetData = aTarget->mImage->Data();
  uint32_t stride = aTarget->mImage->Stride();

  if (aDX == 0) {
    CopyDataRect(tmp, sourceData, stride, aDataRect);
  } else {
    int32_t longLobe = aDX/2;
    int32_t shortLobe = (aDX & 1) ? longLobe : longLobe - 1;
    for (int32_t major = aDataRect.y; major < aDataRect.YMost(); ++major) {
      int32_t ms = major*stride;
      BoxBlur(sourceData + ms, tmp + ms, 4, aDataRect.x, aDataRect.XMost(), longLobe, shortLobe, alphaOnly);
      BoxBlur(tmp + ms, targetData + ms, 4, aDataRect.x, aDataRect.XMost(), shortLobe, longLobe, alphaOnly);
      BoxBlur(targetData + ms, tmp + ms, 4, aDataRect.x, aDataRect.XMost(), longLobe, longLobe, alphaOnly);
    }
  }

  if (aDY == 0) {
    CopyDataRect(targetData, tmp, stride, aDataRect);
  } else {
    int32_t longLobe = aDY/2;
    int32_t shortLobe = (aDY & 1) ? longLobe : longLobe - 1;
    for (int32_t major = aDataRect.x; major < aDataRect.XMost(); ++major) {
      int32_t ms = major*4;
      BoxBlur(tmp + ms, targetData + ms, stride, aDataRect.y, aDataRect.YMost(), longLobe, shortLobe, alphaOnly);
      BoxBlur(targetData + ms, tmp + ms, stride, aDataRect.y, aDataRect.YMost(), shortLobe, longLobe, alphaOnly);
      BoxBlur(tmp + ms, targetData + ms, stride, aDataRect.y, aDataRect.YMost(), longLobe, longLobe, alphaOnly);
    }
  }
}
// Clip aTarget's image to its filter primitive subregion.
// aModifiedRect contains all the pixels which might not be RGBA(0,0,0,0),
// it's relative to the surface data.
static void
ClipTarget(nsSVGFilterInstance* aInstance, const nsSVGFE::Image* aTarget,
           const nsIntRect& aModifiedRect)
{
  nsIntPoint surfaceTopLeft = aInstance->GetSurfaceRect().TopLeft();

  NS_ASSERTION(aInstance->GetSurfaceRect().Contains(aModifiedRect + surfaceTopLeft),
               "Modified data area overflows the surface?");

  nsIntRect clip = aModifiedRect;
  nsSVGUtils::ClipToGfxRect(&clip,
    aTarget->mFilterPrimitiveSubregion - gfxPoint(surfaceTopLeft.x, surfaceTopLeft.y));

  ClearRect(aTarget->mImage, aModifiedRect.x, aModifiedRect.y, aModifiedRect.XMost(), clip.y);
  ClearRect(aTarget->mImage, aModifiedRect.x, clip.y, clip.x, clip.YMost());
  ClearRect(aTarget->mImage, clip.XMost(), clip.y, aModifiedRect.XMost(), clip.YMost());
  ClearRect(aTarget->mImage, aModifiedRect.x, clip.YMost(), aModifiedRect.XMost(), aModifiedRect.YMost());
}
示例#9
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
LayerManagerOGL::BindAndDrawQuadWithTextureRect(LayerProgram *aProg,
        const nsIntRect& aTexCoordRect,
        const nsIntSize& aTexSize,
        GLenum aWrapMode)
{
    GLuint vertAttribIndex =
        aProg->AttribLocation(LayerProgram::VertexAttrib);
    GLuint texCoordAttribIndex =
        aProg->AttribLocation(LayerProgram::TexCoordAttrib);
    NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?");

    // clear any bound VBO so that glVertexAttribPointer() goes back to
    // "pointer mode"
    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);

    // 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;

    if (aWrapMode == LOCAL_GL_REPEAT) {
        rects.addRect(/* dest rectangle */
            0.0f, 0.0f, 1.0f, 1.0f,
            /* tex coords */
            aTexCoordRect.x / GLfloat(aTexSize.width),
            aTexCoordRect.y / GLfloat(aTexSize.height),
            aTexCoordRect.XMost() / GLfloat(aTexSize.width),
            aTexCoordRect.YMost() / GLfloat(aTexSize.height));
    } else {
        GLContext::DecomposeIntoNoRepeatTriangles(aTexCoordRect, aTexSize, rects);
    }

    mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
                                     rects.vertexPointer());

    mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2,
                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
                                     rects.texCoordPointer());

    {
        mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
        {
            mGLContext->fEnableVertexAttribArray(vertAttribIndex);

            mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());

            mGLContext->fDisableVertexAttribArray(vertAttribIndex);
        }
        mGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
    }
}
void
SwapChainD3D9::Present(const nsIntRect &aRect)
{
  RECT r;
  r.left = aRect.x;
  r.top = aRect.y;
  r.right = aRect.XMost();
  r.bottom = aRect.YMost();

  mSwapChain->Present(&r, &r, 0, 0, 0);
}
示例#11
0
void
AndroidGeckoLayerClient::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect)
{
    NS_ASSERTION(!isNull(), "SetFirstPaintViewport called on null layer client!");
    JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
    if (!env)
        return;

    AutoLocalJNIFrame jniFrame(env, 0);
    return env->CallVoidMethod(wrapped_obj, jSetFirstPaintViewport, (float)aOffset.x, (float)aOffset.y, aZoom,
                               (float)aPageRect.x, (float)aPageRect.y, (float)aPageRect.XMost(), (float)aPageRect.YMost(),
                               aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
}
示例#12
0
nsIntRect RotateRect(nsIntRect aRect,
                     const nsIntRect& aBounds,
                     ScreenRotation aRotation)
{
  switch (aRotation) {
    case ROTATION_0:
      return aRect;
    case ROTATION_90:
      return nsIntRect(aRect.Y(),
                       aBounds.Width() - aRect.XMost(),
                       aRect.Height(), aRect.Width());
    case ROTATION_180:
      return nsIntRect(aBounds.Width() - aRect.XMost(),
                       aBounds.Height() - aRect.YMost(),
                       aRect.Width(), aRect.Height());
    case ROTATION_270:
      return nsIntRect(aBounds.Height() - aRect.YMost(),
                       aRect.X(),
                       aRect.Height(), aRect.Width());
    default:
      MOZ_CRASH("Unknown rotation");
  }
}
示例#13
0
static void
ComputeAlphaMask(uint8_t *aData,
                 int32_t aStride,
                 const nsIntRect &aRect,
                 float aOpacity)
{
    for (int32_t y = aRect.y; y < aRect.YMost(); y++) {
        for (int32_t x = aRect.x; x < aRect.XMost(); x++) {
            uint8_t *pixel = aData + aStride * y + 4 * x;
            uint8_t luminance = pixel[GFX_ARGB32_OFFSET_A] * aOpacity;
            memset(pixel, luminance, 4);
        }
    }
}
示例#14
0
already_AddRefed<gfxContext>
ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds)
{
  nsRefPtr<gfxContext> ctx = new gfxContext(mBuffer);

  // Figure out which quadrant to draw in
  PRInt32 xBoundary = mBufferRect.XMost() - mBufferRotation.x;
  PRInt32 yBoundary = mBufferRect.YMost() - mBufferRotation.y;
  XSide sideX = aBounds.XMost() <= xBoundary ? RIGHT : LEFT;
  YSide sideY = aBounds.YMost() <= yBoundary ? BOTTOM : TOP;
  nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
  NS_ASSERTION(quadrantRect.Contains(aBounds), "Messed up quadrants");
  ctx->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y));

  return ctx.forget();
}
示例#15
0
void
nsSVGUtils::ConvertImageDataFromLinearRGB(PRUint8 *data, 
                                          PRInt32 stride,
                                          const nsIntRect &rect)
{
  for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
    for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
      PRUint8 *pixel = data + stride * y + 4 * x;

      pixel[GFX_ARGB32_OFFSET_B] =
        glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_B]];
      pixel[GFX_ARGB32_OFFSET_G] =
        glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_G]];
      pixel[GFX_ARGB32_OFFSET_R] =
        glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_R]];
    }
  }
}
示例#16
0
already_AddRefed<gfxContext>
RotatedContentBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds,
                                                  ContextSource aSource,
                                                  nsIntPoint *aTopLeft)
{
  if (!EnsureBuffer()) {
    return nullptr;
  }

  nsRefPtr<gfxContext> ctx;
  if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
    if (!EnsureBufferOnWhite()) {
      return nullptr;
    }
    MOZ_ASSERT(mDTBuffer && mDTBufferOnWhite);
    RefPtr<DrawTarget> dualDT = Factory::CreateDualDrawTarget(mDTBuffer, mDTBufferOnWhite);
    ctx = new gfxContext(dualDT);
  } else if (aSource == BUFFER_WHITE) {
    if (!EnsureBufferOnWhite()) {
      return nullptr;
    }
    ctx = new gfxContext(mDTBufferOnWhite);
  } else {
    // BUFFER_BLACK, or BUFFER_BOTH with a single buffer.
    ctx = new gfxContext(mDTBuffer);
  }

  // Figure out which quadrant to draw in
  int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
  int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
  XSide sideX = aBounds.XMost() <= xBoundary ? RIGHT : LEFT;
  YSide sideY = aBounds.YMost() <= yBoundary ? BOTTOM : TOP;
  nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
  NS_ASSERTION(quadrantRect.Contains(aBounds), "Messed up quadrants");
  ctx->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y));

  if (aTopLeft) {
    *aTopLeft = nsIntPoint(quadrantRect.x, quadrantRect.y);
  }

  return ctx.forget();
}
示例#17
0
void
nsSVGUtils::PremultiplyImageDataAlpha(PRUint8 *data, 
                                      PRInt32 stride,
                                      const nsIntRect &rect)
{
  for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
    for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
      PRUint8 *pixel = data + stride * y + 4 * x;

      PRUint8 a = pixel[GFX_ARGB32_OFFSET_A];
      if (a == 255)
        continue;

      FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_B],
                         pixel[GFX_ARGB32_OFFSET_B] * a);
      FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_G],
                         pixel[GFX_ARGB32_OFFSET_G] * a);
      FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_R],
                         pixel[GFX_ARGB32_OFFSET_R] * a);
    }
  }
}
示例#18
0
static void
ComputeLinearRGBLuminanceMask(uint8_t *aData,
                              int32_t aStride,
                              const nsIntRect &aRect,
                              float aOpacity)
{
    for (int32_t y = aRect.y; y < aRect.YMost(); y++) {
        for (int32_t x = aRect.x; x < aRect.XMost(); x++) {
            uint8_t *pixel = aData + aStride * y + 4 * x;
            uint8_t a = pixel[GFX_ARGB32_OFFSET_A];

            uint8_t luminance;
            // unpremultiply
            if (a) {
                if (a != 255) {
                    pixel[GFX_ARGB32_OFFSET_B] =
                        (255 * pixel[GFX_ARGB32_OFFSET_B]) / a;
                    pixel[GFX_ARGB32_OFFSET_G] =
                        (255 * pixel[GFX_ARGB32_OFFSET_G]) / a;
                    pixel[GFX_ARGB32_OFFSET_R] =
                        (255 * pixel[GFX_ARGB32_OFFSET_R]) / a;
                }

                /* sRGB -> linearRGB -> intensity */
                luminance =
                    static_cast<uint8_t>
                    ((gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_R]] *
                      0.2125 +
                      gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_G]] *
                      0.7154 +
                      gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_B]] *
                      0.0721) * (a / 255.0) * aOpacity);
            } else {
                luminance = 0;
            }
            memset(pixel, luminance, 4);
        }
    }
}
示例#19
0
/* static */
void
WinUtils::InvalidatePluginAsWorkaround(nsIWidget *aWidget, const nsIntRect &aRect)
{
  aWidget->Invalidate(aRect);

  // XXX - Even more evil workaround!! See bug 762948, flash's bottom
  // level sandboxed window doesn't seem to get our invalidate. We send
  // an invalidate to it manually. This is totally specialized for this
  // bug, for other child window structures this will just be a more or
  // less bogus invalidate but since that should not have any bad
  // side-effects this will have to do for now.
  HWND current = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);

  RECT windowRect;
  RECT parentRect;

  ::GetWindowRect(current, &parentRect);

  HWND next = current;
  do {
    current = next;
    ::EnumChildWindows(current, &EnumFirstChild, (LPARAM)&next);
    ::GetWindowRect(next, &windowRect);
    // This is relative to the screen, adjust it to be relative to the
    // window we're reconfiguring.
    windowRect.left -= parentRect.left;
    windowRect.top -= parentRect.top;
  } while (next != current && windowRect.top == 0 && windowRect.left == 0);

  if (windowRect.top == 0 && windowRect.left == 0) {
    RECT rect;
    rect.left   = aRect.x;
    rect.top    = aRect.y;
    rect.right  = aRect.XMost();
    rect.bottom = aRect.YMost();

    ::InvalidateRect(next, &rect, FALSE);
  }
}
示例#20
0
nsresult
SVGFETileElement::Filter(nsSVGFilterInstance *instance,
                         const nsTArray<const Image*>& aSources,
                         const Image* aTarget,
                         const nsIntRect& rect)
{
  // XXX This code depends on the surface rect containing the filter
  // primitive subregion. ComputeTargetBBox, ComputeNeededSourceBBoxes
  // and ComputeChangeBBox are all pessimal, so that will normally be OK,
  // but nothing clips mFilterPrimitiveSubregion so this should be changed.

  nsIntRect tile;
  bool res = gfxUtils::GfxRectToIntRect(aSources[0]->mFilterPrimitiveSubregion,
                                        &tile);

  NS_ENSURE_TRUE(res, NS_ERROR_FAILURE); // asserts on failure (not 
  if (tile.IsEmpty())
    return NS_OK;

  const nsIntRect &surfaceRect = instance->GetSurfaceRect();
  if (!tile.Intersects(surfaceRect)) {
    // nothing to draw
    return NS_OK;
  }

  // clip tile
  tile = tile.Intersect(surfaceRect);

  // Get it into surface space
  tile -= surfaceRect.TopLeft();

  uint8_t* sourceData = aSources[0]->mImage->Data();
  uint8_t* targetData = aTarget->mImage->Data();
  uint32_t stride = aTarget->mImage->Stride();

  /*
   * priority: left before right before centre
   *             and
   *           top before bottom before centre
   *
   * eg: If we have a target area which is 1.5 times the width of a tile,
   *     then, based on alignment, we get:
   *       'left and right'
   *         or
   *       'left and centre'
   *
   */

  int32_t leftPartialTileWidth;
  int32_t rightPartialTileWidth;
  int32_t centreWidth;
  ComputePartialTileExtents(&leftPartialTileWidth,
                            &rightPartialTileWidth,
                            &centreWidth,
                            rect.x,
                            rect.width,
                            tile.x,
                            tile.width);

  int32_t topPartialTileHeight;
  int32_t bottomPartialTileHeight;
  int32_t centreHeight;
  ComputePartialTileExtents(&topPartialTileHeight,
                            &bottomPartialTileHeight,
                            &centreHeight,
                            rect.y,
                            rect.height,
                            tile.y,
                            tile.height);

  /* We have nine regions of the target area which have to be tiled differetly:
   *
   * Top Left,    Top Middle,    Top Right,
   * Left Middle, Centre,        Right Middle,
   * Bottom Left, Bottom Middle, Bottom Right
   *
   * + Centre is tiled by repeating the tiled image in full.
   * + Top Left, Top Middle and Top Right:
   *     Some of the rows from the top of the tile will be clipped here.
   * + Bottom Left, Bottom Middle and Bottom Right:
   *     Some of the rows from the bottom of the tile will be clipped here.
   * + Top Left, Left Middle and Bottom left:
   *     Some of the columns from the Left of the tile will be clipped here.
   * + Top Right, Right Middle and Bottom Right:
   *     Some of the columns from the right of the tile will be clipped here.
   *
   * If the sizes and positions of the target and tile are such that the tile
   * aligns exactly on any (or all) of the edges, then some (or all) of the
   * regions above (except Centre) will be zero sized.
   */

  nsIntRect targetRects[] = {
    // Top Left
    nsIntRect(rect.x, rect.y, leftPartialTileWidth, topPartialTileHeight),
    // Top Middle
    nsIntRect(rect.x + leftPartialTileWidth,
              rect.y,
              centreWidth,
              topPartialTileHeight),
    // Top Right
    nsIntRect(rect.XMost() - rightPartialTileWidth,
              rect.y,
              rightPartialTileWidth,
              topPartialTileHeight),
    // Left Middle
    nsIntRect(rect.x,
              rect.y + topPartialTileHeight,
              leftPartialTileWidth,
              centreHeight),
    // Centre
    nsIntRect(rect.x + leftPartialTileWidth,
              rect.y + topPartialTileHeight,
              centreWidth,
              centreHeight),
    // Right Middle
    nsIntRect(rect.XMost() - rightPartialTileWidth,
              rect.y + topPartialTileHeight,
              rightPartialTileWidth,
              centreHeight),
    // Bottom Left
    nsIntRect(rect.x,
              rect.YMost() - bottomPartialTileHeight,
              leftPartialTileWidth,
              bottomPartialTileHeight),
    // Bottom Middle
    nsIntRect(rect.x + leftPartialTileWidth,
              rect.YMost() - bottomPartialTileHeight,
              centreWidth,
              bottomPartialTileHeight),
    // Bottom Right
    nsIntRect(rect.XMost() - rightPartialTileWidth,
              rect.YMost() - bottomPartialTileHeight,
              rightPartialTileWidth,
              bottomPartialTileHeight)
  };

  nsIntRect tileRects[] = {
    // Top Left
    nsIntRect(tile.XMost() - leftPartialTileWidth,
              tile.YMost() - topPartialTileHeight,
              leftPartialTileWidth,
              topPartialTileHeight),
    // Top Middle
    nsIntRect(tile.x,
              tile.YMost() - topPartialTileHeight,
              tile.width,
              topPartialTileHeight),
    // Top Right
    nsIntRect(tile.x,
              tile.YMost() - topPartialTileHeight,
              rightPartialTileWidth,
              topPartialTileHeight),
    // Left Middle
    nsIntRect(tile.XMost() - leftPartialTileWidth,
              tile.y,
              leftPartialTileWidth,
              tile.height),
    // Centre
    nsIntRect(tile.x,
              tile.y,
              tile.width,
              tile.height),
    // Right Middle
    nsIntRect(tile.x,
              tile.y,
              rightPartialTileWidth,
              tile.height),
    // Bottom Left
    nsIntRect(tile.XMost() - leftPartialTileWidth,
              tile.y,
              leftPartialTileWidth,
              bottomPartialTileHeight),
    // Bottom Middle
    nsIntRect(tile.x,
              tile.y,
              tile.width,
              bottomPartialTileHeight),
    // Bottom Right
    nsIntRect(tile.x,
              tile.y,
              rightPartialTileWidth,
              bottomPartialTileHeight)
  };

  for (uint32_t i = 0; i < ArrayLength(targetRects); ++i) {
    TilePixels(targetData,
               sourceData,
               targetRects[i],
               tileRects[i],
               stride);
  }

  return NS_OK;
}
示例#21
0
/**
 * Box blur involves looking at one pixel, and setting its value to the average
 * of its neighbouring pixels.
 * @param aInput The input buffer.
 * @param aOutput The output buffer.
 * @param aLeftLobe The number of pixels to blend on the left.
 * @param aRightLobe The number of pixels to blend on the right.
 * @param aWidth The number of columns in the buffers.
 * @param aRows The number of rows in the buffers.
 * @param aSkipRect An area to skip blurring in.
 * XXX shouldn't we pass stride in separately here?
 */
static void
BoxBlurHorizontal(unsigned char* aInput,
                  unsigned char* aOutput,
                  PRInt32 aLeftLobe,
                  PRInt32 aRightLobe,
                  PRInt32 aWidth,
                  PRInt32 aRows,
                  const nsIntRect& aSkipRect)
{
    NS_ASSERTION(aWidth > 0, "Can't handle zero width here");

    PRInt32 boxSize = aLeftLobe + aRightLobe + 1;
    PRBool skipRectCoversWholeRow = 0 >= aSkipRect.x &&
                                    aWidth <= aSkipRect.XMost();

    for (PRInt32 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).
        PRBool inSkipRectY = y >= aSkipRect.y &&
                             y < aSkipRect.YMost();
        if (inSkipRectY && skipRectCoversWholeRow) {
            y = aSkipRect.YMost() - 1;
            continue;
        }

        PRInt32 alphaSum = 0;
        for (PRInt32 i = 0; i < boxSize; i++) {
            PRInt32 pos = i - aLeftLobe;
            // See assertion above; if aWidth is zero, then we would have no
            // valid position to clamp to.
            pos = NS_MAX(pos, 0);
            pos = NS_MIN(pos, aWidth - 1);
            alphaSum += aInput[aWidth * y + pos];
        }
        for (PRInt32 x = 0; x < aWidth; x++) {
            // Check whether we are within the skip rect. If so, go
            // to the next point outside the skip rect.
            if (inSkipRectY && x >= aSkipRect.x &&
                x < aSkipRect.XMost()) {
                x = aSkipRect.XMost();
                if (x >= aWidth)
                    break;

                // Recalculate the neighbouring alpha values for
                // our new point on the surface.
                alphaSum = 0;
                for (PRInt32 i = 0; i < boxSize; i++) {
                    PRInt32 pos = x + i - aLeftLobe;
                    // See assertion above; if aWidth is zero, then we would have no
                    // valid position to clamp to.
                    pos = NS_MAX(pos, 0);
                    pos = NS_MIN(pos, aWidth - 1);
                    alphaSum += aInput[aWidth * y + pos];
                }
            }
            PRInt32 tmp = x - aLeftLobe;
            PRInt32 last = NS_MAX(tmp, 0);
            PRInt32 next = NS_MIN(tmp + boxSize, aWidth - 1);

            aOutput[aWidth * y + x] = alphaSum/boxSize;

            alphaSum += aInput[aWidth * y + next] -
                        aInput[aWidth * y + last];
        }
    }
}
nsresult
nsThebesImage::ThebesDrawTile(gfxContext *thebesContext,
                              nsIDeviceContext* dx,
                              const gfxPoint& offset,
                              const gfxRect& targetRect,
                              const nsIntRect& aSubimageRect,
                              const PRInt32 xPadding,
                              const PRInt32 yPadding)
{
    NS_ASSERTION(xPadding >= 0 && yPadding >= 0, "negative padding");

    if (targetRect.size.width <= 0.0 || targetRect.size.height <= 0.0)
        return NS_OK;

    // don't do anything if we have a transparent pixel source
    if (mSinglePixel && mSinglePixelColor.a == 0.0)
        return NS_OK;

    PRBool doSnap = !(thebesContext->CurrentMatrix().HasNonTranslation());
    PRBool hasPadding = ((xPadding != 0) || (yPadding != 0));
    gfxImageSurface::gfxImageFormat format = mFormat;
    
    gfxPoint tmpOffset = offset;

    if (mSinglePixel && !hasPadding) {
        thebesContext->SetDeviceColor(mSinglePixelColor);
    } else {
        nsRefPtr<gfxASurface> surface;
        PRInt32 width, height;

        if (hasPadding) {
            /* Ugh we have padding; create a temporary surface that's the size of the surface + pad area,
             * and render the image into it first.  Then we'll tile that surface. */
            width = mWidth + xPadding;
            height = mHeight + yPadding;

            // Reject over-wide or over-tall images.
            if (!AllowedImageSize(width, height))
                return NS_ERROR_FAILURE;

            format = gfxASurface::ImageFormatARGB32;
            surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(
                    gfxIntSize(width, height), format);
            if (!surface || surface->CairoStatus()) {
                return NS_ERROR_OUT_OF_MEMORY;
            }

            gfxContext tmpContext(surface);
            if (mSinglePixel) {
                tmpContext.SetDeviceColor(mSinglePixelColor);
            } else {
                tmpContext.SetSource(ThebesSurface());
            }
            tmpContext.SetOperator(gfxContext::OPERATOR_SOURCE);
            tmpContext.Rectangle(gfxRect(0, 0, mWidth, mHeight));
            tmpContext.Fill();
        } else {
            width = mWidth;
            height = mHeight;
            surface = ThebesSurface();
        }
        
        // Scale factor to account for CSS pixels; note that the offset (and 
        // therefore p0) is in device pixels, while the width and height are in
        // CSS pixels.
        gfxFloat scale = gfxFloat(dx->AppUnitsPerDevPixel()) /
                         gfxFloat(nsIDeviceContext::AppUnitsPerCSSPixel());

        if ((aSubimageRect.width < width || aSubimageRect.height < height) &&
            (thebesContext->CurrentMatrix().HasNonTranslation() || scale != 1.0)) {
            // Some of the source image should not be drawn, and we're going
            // to be doing more than just translation, so we might accidentally
            // sample the non-drawn pixels. Avoid that by creating a
            // temporary image representing the portion that will be drawn,
            // with built-in padding since we can't use EXTEND_PAD and
            // EXTEND_REPEAT at the same time for different axes.
            PRInt32 padX = aSubimageRect.width < width ? 1 : 0;
            PRInt32 padY = aSubimageRect.height < height ? 1 : 0;
            PRInt32 tileWidth = PR_MIN(aSubimageRect.width, width);
            PRInt32 tileHeight = PR_MIN(aSubimageRect.height, height);
            
            // This tmpSurface will contain a snapshot of the repeated
            // tile image at (aSubimageRect.x, aSubimageRect.y,
            // tileWidth, tileHeight), with padX padding added to the left
            // and right sides and padY padding added to the top and bottom
            // sides.
            nsRefPtr<gfxASurface> tmpSurface;
            tmpSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(
                    gfxIntSize(tileWidth + 2*padX, tileHeight + 2*padY), format);
            if (!tmpSurface || tmpSurface->CairoStatus()) {
                return NS_ERROR_OUT_OF_MEMORY;
            }

            gfxContext tmpContext(tmpSurface);
            tmpContext.SetOperator(gfxContext::OPERATOR_SOURCE);
            gfxPattern pat(surface);
            pat.SetExtend(gfxPattern::EXTEND_REPEAT);
            
            // Copy the needed portion of the source image to the temporary
            // surface. We also copy over horizontal and/or vertical padding
            // strips one pixel wide, plus the corner pixels if necessary.
            // So in the most general case the temporary surface ends up
            // looking like
            //     P P P ... P P P
            //     P X X ... X X P
            //     P X X ... X X P
            //     ...............
            //     P X X ... X X P
            //     P X X ... X X P
            //     P P P ... P P P
            // Where each P pixel has the color of its nearest source X
            // pixel. We implement this as a loop over all nine possible
            // areas, [padding, body, padding] x [padding, body, padding].
            // Note that we will not need padding on both axes unless
            // we are painting just a single tile, in which case this
            // will hardly ever get called since nsCSSRendering converts
            // the single-tile case to nsLayoutUtils::DrawImage. But this
            // could be called on other paths (XUL trees?) and it's simpler
            // and clearer to do it the general way.
            PRInt32 destY = 0;
            for (PRInt32 y = -1; y <= 1; ++y) {
                PRInt32 stripHeight = y == 0 ? tileHeight : padY;
                if (stripHeight == 0)
                    continue;
                PRInt32 srcY = y == 1 ? aSubimageRect.YMost() - padY : aSubimageRect.y;
                
                PRInt32 destX = 0;
                for (PRInt32 x = -1; x <= 1; ++x) {
                    PRInt32 stripWidth = x == 0 ? tileWidth : padX;
                    if (stripWidth == 0)
                        continue;
                    PRInt32 srcX = x == 1 ? aSubimageRect.XMost() - padX : aSubimageRect.x;

                    gfxMatrix patMat;
                    patMat.Translate(gfxPoint(srcX - destX, srcY - destY));
                    pat.SetMatrix(patMat);
                    tmpContext.SetPattern(&pat);
                    tmpContext.Rectangle(gfxRect(destX, destY, stripWidth, stripHeight));
                    tmpContext.Fill();
                    tmpContext.NewPath();
                    
                    destX += stripWidth;
                }
                destY += stripHeight;
            }

            // tmpOffset was the top-left of the old tile image. Make it
            // the top-left of the new tile image. Note that tmpOffset is
            // in destination coordinate space so we have to scale our
            // CSS pixels.
            tmpOffset += gfxPoint(aSubimageRect.x - padX, aSubimageRect.y - padY)/scale;
            
            surface = tmpSurface;
        }

        gfxMatrix patMat;
        gfxPoint p0;

        p0.x = - floor(tmpOffset.x + 0.5);
        p0.y = - floor(tmpOffset.y + 0.5);
        patMat.Scale(scale, scale);
        patMat.Translate(p0);

        gfxPattern pat(surface);
        pat.SetExtend(gfxPattern::EXTEND_REPEAT);
        pat.SetMatrix(patMat);

#ifndef XP_MACOSX
        if (scale < 1.0) {
            // See bug 324698.  This is a workaround.  See comments
            // by the earlier SetFilter call.
            pat.SetFilter(0);
        }
#endif

        thebesContext->SetPattern(&pat);
    }

    gfxContext::GraphicsOperator op = thebesContext->CurrentOperator();
    if (op == gfxContext::OPERATOR_OVER && format == gfxASurface::ImageFormatRGB24)
        thebesContext->SetOperator(gfxContext::OPERATOR_SOURCE);

    thebesContext->NewPath();
    thebesContext->Rectangle(targetRect, doSnap);
    thebesContext->Fill();

    thebesContext->SetOperator(op);
    thebesContext->SetDeviceColor(gfxRGBA(0,0,0,0));

    return NS_OK;
}
nsresult
SVGFEMorphologyElement::Filter(nsSVGFilterInstance* instance,
                               const nsTArray<const Image*>& aSources,
                               const Image* aTarget,
                               const nsIntRect& rect)
{
  int32_t rx, ry;
  GetRXY(&rx, &ry, *instance);

  if (rx < 0 || ry < 0) {
    // XXX SVGContentUtils::ReportToConsole()
    return NS_OK;
  }
  if (rx == 0 && ry == 0) {
    return NS_OK;
  }

  // Clamp radii to prevent completely insane values:
  rx = std::min(rx, 100000);
  ry = std::min(ry, 100000);

  uint8_t* sourceData = aSources[0]->mImage->Data();
  uint8_t* targetData = aTarget->mImage->Data();
  int32_t stride = aTarget->mImage->Stride();
  uint8_t extrema[4];         // RGBA magnitude of extrema
  uint16_t op = mEnumAttributes[OPERATOR].GetAnimValue();

  // Scan the kernel for each pixel to determine max/min RGBA values.
  for (int32_t y = rect.y; y < rect.YMost(); y++) {
    int32_t startY = std::max(0, y - ry);
    // We need to read pixels not just in 'rect', which is limited to
    // the dirty part of our filter primitive subregion, but all pixels in
    // the given radii from the source surface, so use the surface size here.
    int32_t endY = std::min(y + ry, instance->GetSurfaceHeight() - 1);
    for (int32_t x = rect.x; x < rect.XMost(); x++) {
      int32_t startX = std::max(0, x - rx);
      int32_t endX = std::min(x + rx, instance->GetSurfaceWidth() - 1);
      int32_t targIndex = y * stride + 4 * x;

      for (int32_t i = 0; i < 4; i++) {
        extrema[i] = sourceData[targIndex + i];
      }
      for (int32_t y1 = startY; y1 <= endY; y1++) {
        for (int32_t x1 = startX; x1 <= endX; x1++) {
          for (int32_t i = 0; i < 4; i++) {
            uint8_t pixel = sourceData[y1 * stride + 4 * x1 + i];
            if ((extrema[i] > pixel &&
                 op == SVG_OPERATOR_ERODE) ||
                (extrema[i] < pixel &&
                 op == SVG_OPERATOR_DILATE)) {
              extrema[i] = pixel;
            }
          }
        }
      }
      targetData[targIndex  ] = extrema[0];
      targetData[targIndex+1] = extrema[1];
      targetData[targIndex+2] = extrema[2];
      targetData[targIndex+3] = extrema[3];
    }
  }
  return NS_OK;
}