hash.c (3717B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21 22#include <cairo/cairo.h> 23 24#include <stdint.h> 25#include <string.h> 26 27/* 28 * Arbitrary hash function whhich maps ALL 32-bit numbers onto 24-bit numbers 29 * evenly, while guaranteeing that all 24-bit numbers are mapped onto 30 * themselves. 31 */ 32unsigned int _guac_hash_32to24(unsigned int value) { 33 34 /* Grab highest-order byte */ 35 unsigned int upper = value & 0xFF000000; 36 37 /* XOR upper with lower three bytes, truncate to 24-bit */ 38 return 39 (value & 0xFFFFFF) 40 ^ (upper >> 8) 41 ^ (upper >> 16) 42 ^ (upper >> 24); 43 44} 45 46/** 47 * Rotates a given 32-bit integer by N bits. 48 * 49 * NOTE: We probably should check for available bitops.h macros first. 50 */ 51unsigned int _guac_rotate(unsigned int value, int amount) { 52 53 /* amount = amount % 32 */ 54 amount &= 0x1F; 55 56 /* Return rotated amount */ 57 return (value >> amount) | (value << (32 - amount)); 58 59} 60 61unsigned int guac_hash_surface(cairo_surface_t* surface) { 62 63 /* Init to zero */ 64 unsigned int hash_value = 0; 65 66 int x, y; 67 68 /* Get image data and metrics */ 69 unsigned char* data = cairo_image_surface_get_data(surface); 70 int width = cairo_image_surface_get_width(surface); 71 int height = cairo_image_surface_get_height(surface); 72 int stride = cairo_image_surface_get_stride(surface); 73 74 for (y=0; y<height; y++) { 75 76 /* Get current row */ 77 uint32_t* row = (uint32_t*) data; 78 data += stride; 79 80 for (x=0; x<width; x++) { 81 82 /* Get color at current pixel */ 83 unsigned int color = *row; 84 row++; 85 86 /* Compute next hash */ 87 hash_value = 88 _guac_rotate(hash_value, 1) ^ color ^ 0x1B872E69; 89 90 } 91 92 } /* end for each row */ 93 94 /* Done */ 95 return _guac_hash_32to24(hash_value); 96 97} 98 99int guac_surface_cmp(cairo_surface_t* a, cairo_surface_t* b) { 100 101 /* Surface A metrics */ 102 unsigned char* data_a = cairo_image_surface_get_data(a); 103 int width_a = cairo_image_surface_get_width(a); 104 int height_a = cairo_image_surface_get_height(a); 105 int stride_a = cairo_image_surface_get_stride(a); 106 107 /* Surface B metrics */ 108 unsigned char* data_b = cairo_image_surface_get_data(b); 109 int width_b = cairo_image_surface_get_width(b); 110 int height_b = cairo_image_surface_get_height(b); 111 int stride_b = cairo_image_surface_get_stride(b); 112 113 int y; 114 115 /* If core dimensions differ, just compare those. Done. */ 116 if (width_a != width_b) return width_a - width_b; 117 if (height_a != height_b) return height_a - height_b; 118 119 for (y=0; y<height_a; y++) { 120 121 /* Compare row. If different, use that result. */ 122 int cmp_result = memcmp(data_a, data_b, width_a * 4); 123 if (cmp_result != 0) 124 return cmp_result; 125 126 /* Next row */ 127 data_a += stride_a; 128 data_b += stride_b; 129 130 } 131 132 /* Otherwise, same. */ 133 return 0; 134 135}