Пример #1
0
void computeMD5HashStringForContext(CGContextRef bitmapContext, char hashString[33])
{
    ASSERT(CGBitmapContextGetBitsPerPixel(bitmapContext) == 32); // ImageDiff assumes 32 bit RGBA, we must as well.
    size_t pixelsHigh = CGBitmapContextGetHeight(bitmapContext);
    size_t pixelsWide = CGBitmapContextGetWidth(bitmapContext);
    size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmapContext);
    
    // We need to swap the bytes to ensure consistent hashes independently of endianness
    MD5 md5;
    unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmapContext));
#if PLATFORM(MAC)
    if ((CGBitmapContextGetBitmapInfo(bitmapContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Big) {
        for (unsigned row = 0; row < pixelsHigh; row++) {
            Vector<uint8_t> buffer(4 * pixelsWide);
            for (unsigned column = 0; column < pixelsWide; column++)
                buffer[column] = OSReadLittleInt32(bitmapData, 4 * column);
            md5.addBytes(buffer);
            bitmapData += bytesPerRow;
        }
    } else
#endif
    {
        for (unsigned row = 0; row < pixelsHigh; row++) {
            md5.addBytes(bitmapData, 4 * pixelsWide);
            bitmapData += bytesPerRow;
        }
    }

    Vector<uint8_t, 16> hash;
    md5.checksum(hash);
    
    hashString[0] = '\0';
    for (int i = 0; i < 16; i++)
        snprintf(hashString, 33, "%s%02x", hashString, hash[i]);
}
Пример #2
0
static void getMD5HashStringForBitmap(CGContextRef bitmap, char string[33])
{
    MD5_CTX md5Context;
    unsigned char hash[16];

    size_t bitsPerPixel = CGBitmapContextGetBitsPerPixel(bitmap);
    ASSERT(bitsPerPixel == 32); // ImageDiff assumes 32 bit RGBA, we must as well.
    size_t bytesPerPixel = bitsPerPixel / 8;
    size_t pixelsHigh = CGBitmapContextGetHeight(bitmap);
    size_t pixelsWide = CGBitmapContextGetWidth(bitmap);
    size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmap);
    ASSERT(bytesPerRow >= (pixelsWide * bytesPerPixel));

    MD5_Init(&md5Context);
    unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmap));
    for (unsigned row = 0; row < pixelsHigh; row++) {
        MD5_Update(&md5Context, bitmapData, static_cast<unsigned>(pixelsWide * bytesPerPixel));
        bitmapData += bytesPerRow;
    }
    MD5_Final(hash, &md5Context);

    string[0] = '\0';
    for (int i = 0; i < 16; i++)
        snprintf(string, 33, "%s%02x", string, hash[i]);
}
Пример #3
0
SourceSurfaceCGBitmapContext::SourceSurfaceCGBitmapContext(DrawTargetCG *aDrawTarget)
{
  mDrawTarget = aDrawTarget;
  mFormat = aDrawTarget->GetFormat();
  mCg = (CGContextRef)aDrawTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT);
  if (!mCg)
    abort();

  mSize.width = CGBitmapContextGetWidth(mCg);
  mSize.height = CGBitmapContextGetHeight(mCg);
  mStride = CGBitmapContextGetBytesPerRow(mCg);
  mData = CGBitmapContextGetData(mCg);

  mImage = nullptr;
}
/*	createMaskFromAlphaOnlyContext creates a CGImageRef
	from an alpha-only bitmap context. Calling this routine
	transfers 'ownership' of the raster data in the bitmap 
	context, to the image. If the image can't be created, this 
	routine frees the memory associated with the raster. 
*/
static CGImageRef createMaskFromAlphaOnlyContext(CGContextRef alphaContext)
{
    CGImageRef mask;
	unsigned char *rasterData = CGBitmapContextGetData(alphaContext);
    size_t imageDataSize = CGBitmapContextGetBytesPerRow(alphaContext)*
								CGBitmapContextGetHeight(alphaContext);
    float invertDecode[] = { 1. , 0. };
        
	if(rasterData == NULL){
		fprintf(stderr, "Context is not a bitmap context!\n");
		return NULL;
	}

    // Create the data provider from the image data.
    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, 
					    rasterData,
					    imageDataSize,
					    releaseBitmapContextImageData);

    if(dataProvider == NULL){
		// Must free the memory if the data provider couldn't be created
		// since this routine now owns it.
		free(rasterData);
		fprintf(stderr, "Couldn't create data provider!\n");
		return NULL;
    }
    mask = CGImageMaskCreate(CGBitmapContextGetWidth(alphaContext), 
			  CGBitmapContextGetHeight(alphaContext), 
			  CGBitmapContextGetBitsPerComponent(alphaContext), 
			  CGBitmapContextGetBitsPerPixel(alphaContext), 
			  CGBitmapContextGetBytesPerRow(alphaContext), 
			  dataProvider,
	// The decode is an inverted decode since a mask has the opposite
	// sense than alpha, i.e. 0 in a mask paints 100% and 1 in a mask
	// paints nothing.
			  invertDecode,
			  true);

    // Release the data provider since the mask retains it.
    CGDataProviderRelease(dataProvider);

    if(mask == NULL){
		fprintf(stderr, "Couldn't create image mask!\n");
		return NULL;
    }
    return mask;
}
/*	createImageFromBitmapContext creates a CGImageRef
	from a bitmap context. Calling this routine
	transfers 'ownership' of the raster data
	in the bitmap context, to the image. If the
	image can't be created, this routine frees
	the memory associated with the raster. 
*/
CGImageRef createImageFromBitmapContext(CGContextRef c)
{
    CGImageRef image;
	unsigned char *rasterData = CGBitmapContextGetData(c);
    size_t imageDataSize = 
		CGBitmapContextGetBytesPerRow(c)*CGBitmapContextGetHeight(c);
	
	if(rasterData == NULL){
		fprintf(stderr, "Context is not a bitmap context!\n");
		return NULL;
	}
	
    // Create the data provider from the image data, using
	// the image releaser function releaseBitmapContextImageData.
    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL,
					    rasterData,
					    imageDataSize,
					    releaseBitmapContextImageData);
    if(dataProvider == NULL){
		// Since this routine owns the raster memory, it must
		// free it if it can't create the data provider.
		free(rasterData);
		fprintf(stderr, "Couldn't create data provider!\n");
		return NULL;
    }
	// Now create the image. The parameters for the image closely match
	// the parameters of the bitmap context. This code uses a NULL
	// decode array and shouldInterpolate is true.
    image = CGImageCreate(CGBitmapContextGetWidth(c), 
			  CGBitmapContextGetHeight(c), 
			  CGBitmapContextGetBitsPerComponent(c), 
			  CGBitmapContextGetBitsPerPixel(c), 
			  CGBitmapContextGetBytesPerRow(c), 
			  CGBitmapContextGetColorSpace(c),
			  myCGContextGetBitmapInfo(c),
			  dataProvider,
			  NULL,
			  true,
			  kCGRenderingIntentDefault);
    // Release the data provider since the image retains it.
    CGDataProviderRelease(dataProvider);
    if(image == NULL){
		fprintf(stderr, "Couldn't create image!\n");
		return NULL;
    }
    return image;
}
Пример #6
0
// Updates the contents of the root layer texture that fall inside the updateRect
// and re-composits all sublayers.
void LayerRendererChromium::drawLayers(const IntRect& updateRect, const IntRect& visibleRect,
                                       const IntRect& contentRect, const IntPoint& scrollPosition)
{
    ASSERT(m_hardwareCompositing);

    if (!m_rootLayer)
        return;

    makeContextCurrent();

    GLC(glBindTexture(GL_TEXTURE_2D, m_rootLayerTextureId));

    // If the size of the visible area has changed then allocate a new texture
    // to store the contents of the root layer and adjust the projection matrix
    // and viewport.
    int visibleRectWidth = visibleRect.width();
    int visibleRectHeight = visibleRect.height();
    if (visibleRectWidth != m_rootLayerTextureWidth || visibleRectHeight != m_rootLayerTextureHeight) {
        m_rootLayerTextureWidth = visibleRect.width();
        m_rootLayerTextureHeight = visibleRect.height();

        m_projectionMatrix = orthoMatrix(0, visibleRectWidth, visibleRectHeight, 0, -1000, 1000);
        GLC(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
    }

    // The GL viewport covers the entire visible area, including the scrollbars.
    GLC(glViewport(0, 0, visibleRectWidth, visibleRectHeight));

    // Bind the common vertex attributes used for drawing all the layers.
    LayerChromium::prepareForDraw(layerSharedValues());

    // FIXME: These calls can be made once, when the compositor context is initialized.
    GLC(glDisable(GL_DEPTH_TEST));
    GLC(glDisable(GL_CULL_FACE));
    GLC(glDepthFunc(GL_LEQUAL));
    GLC(glClearStencil(0));

    if (m_scrollPosition == IntPoint(-1, -1))
        m_scrollPosition = scrollPosition;

    IntPoint scrollDelta = toPoint(scrollPosition - m_scrollPosition);
    // Scroll only when the updateRect contains pixels for the newly uncovered region to avoid flashing.
    if ((scrollDelta.x() && updateRect.width() >= abs(scrollDelta.x()) && updateRect.height() >= contentRect.height())
        || (scrollDelta.y() && updateRect.height() >= abs(scrollDelta.y()) && updateRect.width() >= contentRect.width())) {
        // Scrolling works as follows: We render a quad with the current root layer contents
        // translated by the amount the page has scrolled since the last update and then read the
        // pixels of the content area (visible area excluding the scroll bars) back into the
        // root layer texture. The newly exposed area is subesquently filled as usual with
        // the contents of the updateRect.
        TransformationMatrix scrolledLayerMatrix;
#if PLATFORM(SKIA)
        float scaleFactor = 1.0f;
#elif PLATFORM(CG)
        // Because the contents of the OpenGL texture are inverted
        // vertically compared to the Skia backend, we need to move
        // the backing store in the opposite direction.
        float scaleFactor = -1.0f;
#else
#error "Need to implement for your platform."
#endif

        scrolledLayerMatrix.translate3d(0.5 * visibleRect.width() - scrollDelta.x(),
            0.5 * visibleRect.height() + scaleFactor * scrollDelta.y(), 0);
        scrolledLayerMatrix.scale3d(1, -1, 1);

        useShader(m_scrollShaderProgram);
        GLC(glUniform1i(m_scrollShaderSamplerLocation, 0));
        LayerChromium::drawTexturedQuad(m_projectionMatrix, scrolledLayerMatrix,
                                        visibleRect.width(), visibleRect.height(), 1,
                                        m_scrollShaderMatrixLocation, -1);

        GLC(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height()));
        m_scrollPosition = scrollPosition;
    } else if (abs(scrollDelta.y()) > contentRect.height() || abs(scrollDelta.x()) > contentRect.width()) {
        // Scrolling larger than the contentRect size does not preserve any of the pixels, so there is
        // no need to copy framebuffer pixels back into the texture.
        m_scrollPosition = scrollPosition;
    }

    // FIXME: The following check should go away when the compositor renders independently from its own thread.
    // Ignore a 1x1 update rect at (0, 0) as that's used a way to kick off a redraw for the compositor.
    if (!(!updateRect.x() && !updateRect.y() && updateRect.width() == 1 && updateRect.height() == 1)) {
        // Update the root layer texture.
        ASSERT((updateRect.x() + updateRect.width() <= m_rootLayerTextureWidth)
               && (updateRect.y() + updateRect.height() <= m_rootLayerTextureHeight));

#if PLATFORM(SKIA)
        // Get the contents of the updated rect.
        const SkBitmap bitmap = m_rootLayerCanvas->getDevice()->accessBitmap(false);
        int rootLayerWidth = bitmap.width();
        int rootLayerHeight = bitmap.height();
        ASSERT(rootLayerWidth == updateRect.width() && rootLayerHeight == updateRect.height());
        void* pixels = bitmap.getPixels();

        // Copy the contents of the updated rect to the root layer texture.
        GLC(glTexSubImage2D(GL_TEXTURE_2D, 0, updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height(), GL_RGBA, GL_UNSIGNED_BYTE, pixels));
#elif PLATFORM(CG)
        // Get the contents of the updated rect.
        ASSERT(static_cast<int>(CGBitmapContextGetWidth(m_rootLayerCGContext.get())) == updateRect.width() && static_cast<int>(CGBitmapContextGetHeight(m_rootLayerCGContext.get())) == updateRect.height());
        void* pixels = m_rootLayerBackingStore.data();

        // Copy the contents of the updated rect to the root layer texture.
        // The origin is at the lower left in Core Graphics' coordinate system. We need to correct for this here.
        GLC(glTexSubImage2D(GL_TEXTURE_2D, 0,
                            updateRect.x(), m_rootLayerTextureHeight - updateRect.y() - updateRect.height(),
                            updateRect.width(), updateRect.height(),
                            GL_RGBA, GL_UNSIGNED_BYTE, pixels));
#else
#error "Need to implement for your platform."
#endif
    }

    glClearColor(0, 0, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Render the root layer using a quad that takes up the entire visible area of the window.
    // We reuse the shader program used by ContentLayerChromium.
    const ContentLayerChromium::SharedValues* contentLayerValues = contentLayerSharedValues();
    useShader(contentLayerValues->contentShaderProgram());
    GLC(glUniform1i(contentLayerValues->shaderSamplerLocation(), 0));
    TransformationMatrix layerMatrix;
    layerMatrix.translate3d(visibleRect.width() * 0.5f, visibleRect.height() * 0.5f, 0);
    LayerChromium::drawTexturedQuad(m_projectionMatrix, layerMatrix,
                                    visibleRect.width(), visibleRect.height(), 1,
                                    contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation());

    // If culling is enabled then we will cull the backface.
    GLC(glCullFace(GL_BACK));
    // The orthographic projection is setup such that Y starts at zero and
    // increases going down the page so we need to adjust the winding order of
    // front facing triangles.
    GLC(glFrontFace(GL_CW));

    // The shader used to render layers returns pre-multiplied alpha colors
    // so we need to send the blending mode appropriately.
    GLC(glEnable(GL_BLEND));
    GLC(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));

    // Translate all the composited layers by the scroll position.
    TransformationMatrix matrix;
    matrix.translate3d(-m_scrollPosition.x(), -m_scrollPosition.y(), 0);

    // Traverse the layer tree and update the layer transforms.
    float opacity = 1;
    const Vector<RefPtr<LayerChromium> >& sublayers = m_rootLayer->getSublayers();
    size_t i;
    for (i = 0; i < sublayers.size(); i++)
        updateLayersRecursive(sublayers[i].get(), matrix, opacity);

    m_rootVisibleRect = visibleRect;

    // Enable scissoring to avoid rendering composited layers over the scrollbars.
    GLC(glEnable(GL_SCISSOR_TEST));
    FloatRect scissorRect(contentRect);
    // The scissorRect should not include the scroll offset.
    scissorRect.move(-m_scrollPosition.x(), -m_scrollPosition.y());
    scissorToRect(scissorRect);

    // Clear the stencil buffer to 0.
    GLC(glClear(GL_STENCIL_BUFFER_BIT));
    // Disable writes to the stencil buffer.
    GLC(glStencilMask(0));

    // Traverse the layer tree one more time to draw the layers.
    for (i = 0; i < sublayers.size(); i++)
        drawLayersRecursive(sublayers[i].get(), scissorRect);

    GLC(glDisable(GL_SCISSOR_TEST));

    m_gles2Context->swapBuffers();

    m_needsDisplay = false;
}