undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
164
test/jdk/java/awt/font/GlyphVector/GlyphVectorGsubTest.java
Normal file
164
test/jdk/java/awt/font/GlyphVector/GlyphVectorGsubTest.java
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8353230
|
||||
* @summary Regression test for TrueType font GSUB substitutions.
|
||||
*/
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
public class GlyphVectorGsubTest {
|
||||
|
||||
/**
|
||||
* <p>Font created for this test which contains two GSUB substitutions: a
|
||||
* "liga" ligature for "a" + "b" which requires that the ligature support
|
||||
* be enabled, and a "ccmp" ligature for an emoji sequence which does not
|
||||
* require that ligatures be explicitly enabled.
|
||||
*
|
||||
* <p>The following FontForge Python script was used to generate this font:
|
||||
*
|
||||
* <pre>
|
||||
* import fontforge
|
||||
* import base64
|
||||
*
|
||||
* def draw(glyph, width, height):
|
||||
* pen = glyph.glyphPen()
|
||||
* pen.moveTo((100, 100))
|
||||
* pen.lineTo((100, 100 + height))
|
||||
* pen.lineTo((100 + width, 100 + height))
|
||||
* pen.lineTo((100 + width, 100))
|
||||
* pen.closePath()
|
||||
* glyph.draw(pen)
|
||||
* pen = None
|
||||
*
|
||||
* font = fontforge.font()
|
||||
* font.encoding = 'UnicodeFull'
|
||||
* font.design_size = 16
|
||||
* font.em = 2048
|
||||
* font.ascent = 1638
|
||||
* font.descent = 410
|
||||
* font.familyname = 'Test'
|
||||
* font.fontname = 'Test'
|
||||
* font.fullname = 'Test'
|
||||
* font.copyright = ''
|
||||
* font.autoWidth(0, 0, 2048)
|
||||
*
|
||||
* font.addLookup('ligatures', 'gsub_ligature', (), (('liga',(('latn',('dflt')),)),))
|
||||
* font.addLookupSubtable('ligatures', 'sub1')
|
||||
*
|
||||
* font.addLookup('sequences', 'gsub_ligature', (), (('ccmp',(('latn',('dflt')),)),))
|
||||
* font.addLookupSubtable('sequences', 'sub2')
|
||||
*
|
||||
* space = font.createChar(0x20)
|
||||
* space.width = 600
|
||||
*
|
||||
* # create glyphs: a, b, ab
|
||||
*
|
||||
* for char in list('ab'):
|
||||
* glyph = font.createChar(ord(char))
|
||||
* draw(glyph, 400, 100)
|
||||
* glyph.width = 600
|
||||
*
|
||||
* ab = font.createChar(-1, 'ab')
|
||||
* ab.addPosSub('sub1', ('a', 'b'))
|
||||
* draw(ab, 400, 400)
|
||||
* ab.width = 600
|
||||
*
|
||||
* # create glyphs for "woman" emoji sequence
|
||||
*
|
||||
* components = []
|
||||
* woman = '\U0001F471\U0001F3FD\u200D\u2640\uFE0F'
|
||||
* for char in list(woman):
|
||||
* glyph = font.createChar(ord(char))
|
||||
* draw(glyph, 400, 800)
|
||||
* glyph.width = 600
|
||||
* components.append(glyph.glyphname)
|
||||
*
|
||||
* del components[-1] # remove last
|
||||
* seq = font.createChar(-1, 'seq')
|
||||
* seq.addPosSub('sub2', components)
|
||||
* draw(seq, 400, 1200)
|
||||
* seq.width = 600
|
||||
*
|
||||
* # save font to file
|
||||
*
|
||||
* ttf = 'test.ttf' # TrueType
|
||||
* t64 = 'test.ttf.txt' # TrueType Base64
|
||||
*
|
||||
* font.generate(ttf)
|
||||
*
|
||||
* with open(ttf, 'rb') as f1:
|
||||
* encoded = base64.b64encode(f1.read())
|
||||
* with open(t64, 'wb') as f2:
|
||||
* f2.write(encoded)
|
||||
* </pre>
|
||||
*/
|
||||
private static final String TTF_BYTES = "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";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
byte[] ttfBytes = Base64.getDecoder().decode(TTF_BYTES);
|
||||
ByteArrayInputStream ttfStream = new ByteArrayInputStream(ttfBytes);
|
||||
Font f1 = Font.createFont(Font.TRUETYPE_FONT, ttfStream).deriveFont(80f);
|
||||
|
||||
// Test emoji sequence, using "ccmp" feature and ZWJ (zero-width joiner):
|
||||
// - person with blonde hair
|
||||
// - emoji modifier fitzpatrick type 4
|
||||
// - zero-width joiner
|
||||
// - female sign
|
||||
// - variation selector 16
|
||||
// Does not require the use of the TextAttribute.LIGATURES_ON attribute.
|
||||
char[] text1 = "\ud83d\udc71\ud83c\udffd\u200d\u2640\ufe0f".toCharArray();
|
||||
FontRenderContext frc = new FontRenderContext(null, true, true);
|
||||
GlyphVector gv1 = f1.layoutGlyphVector(frc, text1, 0, text1.length, 0);
|
||||
checkOneGlyph(gv1, text1, 12);
|
||||
|
||||
// Test regular ligature, using "liga" feature: "ab" -> replacement
|
||||
// Requires the use of the TextAttribute.LIGATURES_ON attribute.
|
||||
char[] text2 = "ab".toCharArray();
|
||||
Font f2 = f1.deriveFont(Map.of(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON));
|
||||
GlyphVector gv2 = f2.layoutGlyphVector(frc, text2, 0, text2.length, 0);
|
||||
checkOneGlyph(gv2, text2, 11);
|
||||
}
|
||||
|
||||
private static void checkOneGlyph(GlyphVector gv, char[] text, int expectedCode) {
|
||||
int glyphs = gv.getNumGlyphs();
|
||||
if (glyphs != 1) {
|
||||
throw new RuntimeException("Unexpected number of glyphs for text " +
|
||||
new String(text) + ": " + glyphs);
|
||||
}
|
||||
int code = gv.getGlyphCode(0);
|
||||
if (code != expectedCode) {
|
||||
throw new RuntimeException("Unexpected glyph code for text " +
|
||||
new String(text) + ": " + expectedCode + " != " + code);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue