I Use This!
Very High Activity

News

Analyzed about 10 hours ago. based on code collected about 16 hours ago.
Posted over 9 years ago by [email protected] (Matt Brubeck)
I’m returning at last to my series on building a simple HTML rendering engine: ... [More] Part 1: Getting started Part 2: HTML Part 3: CSS Part 4: Style Part 5: Boxes Part 6: Block layout Part 7: Painting 101 In this article, I will add very basic painting code. This code takes the tree of boxes from the layout module and turns them into an array of pixels. This process is also known as “rasterization.” Browsers usually implement rasterization with the help of graphics APIs and libraries like Skia, Cairo, Direct2D, and so on. These APIs provide functions for painting polygons, lines, curves, gradients, and text. For now, I’m going to write my own rasterizer that can only paint one thing: rectangles. Eventually I want to implement text rendering. At that point, I may throw away this toy painting code and switch to a “real” 2D graphics library. But for now, rectangles are sufficient to turn the output of my block layout algorithm into pictures. Catching Up Since my last post, I’ve made some small changes to the code from previous articles. These includes some minor refactoring, and some updates to keep the code compatible with the latest Rust nightly builds. None of these changes are vital to understanding the code, but if you’re curious, check the commit history. Building the Display List Before painting, we will walk through the layout tree and build a display list. This is a list of graphics operations like “draw a circle” or “draw a string of text.” Or in our case, just “draw a rectangle.” Why put commands into a display list, rather than execute them immediately? The display list is useful for a several reasons. You can search it for items that will be completely covered up by later operations, and remove them to eliminate wasted painting. You can modify and re-use the display list in cases where you know only certain items have changed. And you can use the same display list to generate different types of output: for example, pixels for displaying on a screen, or vector graphics for sending to a printer. Robinson’s display list is a vector of DisplayCommands. For now there is only one type of DisplayCommand, a solid-color rectangle: type DisplayList = Vec<DisplayCommand>; enum DisplayCommand { SolidColor(Color, Rect), // insert more commands here } To build the display list, we walk through the layout tree and generate a series of commands for each box. First we draw the box’s background, then we draw its borders and content on top of the background. fn build_display_list(layout_root: &LayoutBox) -> DisplayList { let mut list = Vec::new(); render_layout_box(&mut list, layout_root); return list; } fn render_layout_box(list: &mut DisplayList, layout_box: &LayoutBox) { render_background(list, layout_box); render_borders(list, layout_box); // TODO: render text for child in layout_box.children.iter() { render_layout_box(list, child); } } By default, HTML elements are stacked in the order they appear: If two elements overlap, the later one is drawn on top of the earlier one. This is reflected in our display list, which will draw the elements in the same order they appear in the DOM tree. If this code supported the z-index property, then individual elements would be able to override this stacking order, and we’d need to sort the display list accordingly. The background is easy. It’s just a solid rectangle. If no background color is specified, then the background is transparent and we don’t need to generate a display command. fn render_background(list: &mut DisplayList, layout_box: &LayoutBox) { get_color(layout_box, "background").map(|color| list.push(SolidColor(color, layout_box.dimensions.border_box()))); } /// Return the specified color for CSS property `name`, or None if no color was specified. fn get_color(layout_box: &LayoutBox, name: &str) -> Option<Color> { match layout_box.box_type { BlockNode(style) | InlineNode(style) => match style.value(name) { Some(ColorValue(color)) => Some(color), _ => None }, AnonymousBlock => None } } The borders are similar, but instead of a single rectangle we draw four—one for each edge of the box. fn render_borders(list: &mut DisplayList, layout_box: &LayoutBox) { let color = match get_color(layout_box, "border-color") { Some(color) => color, _ => return // bail out if no border-color is specified }; let d = &layout_box.dimensions; let border_box = d.border_box(); // Left border list.push(SolidColor(color, Rect { x: border_box.x, y: border_box.y, width: d.border.left, height: border_box.height, })); // Right border list.push(SolidColor(color, Rect { x: border_box.x + border_box.width - d.border.right, y: border_box.y, width: d.border.right, height: border_box.height, })); // Top border list.push(SolidColor(color, Rect { x: border_box.x, y: border_box.y, width: border_box.width, height: d.border.top, })); // Bottom border list.push(SolidColor(color, Rect { x: border_box.x, y: border_box.y + border_box.height - d.border.bottom, width: border_box.width, height: d.border.bottom, })); } Next the rendering function will draw each of the box’s children, until the entire layout tree has been translated into display commands. Rasterization Now that we’ve built the display list, we need to turn it into pixels by executing each DisplayCommand. We’ll store the pixels in a Canvas: struct Canvas { pixels: Vec<Color>, width: uint, height: uint, } impl Canvas { /// Create a blank canvas fn new(width: uint, height: uint) -> Canvas { let white = Color { r: 255, g: 255, b: 255, a: 255 }; return Canvas { pixels: Vec::from_elem(width * height, white), width: width, height: height, } } // ... } To paint a rectangle on the canvas, we just loop through its rows and columns, using a helper method to make sure we don’t go outside the bounds of our canvas. fn paint_item(&mut self, item: &DisplayCommand) { match item { &SolidColor(color, rect) => { // Clip the rectangle to the canvas boundaries. let x0 = rect.x.clamp(0.0, self.width as f32) as uint; let y0 = rect.y.clamp(0.0, self.height as f32) as uint; let x1 = (rect.x + rect.width).clamp(0.0, self.width as f32) as uint; let y1 = (rect.y + rect.height).clamp(0.0, self.height as f32) as uint; for y in range(y0, y1) { for x in range(x0, x1) { // TODO: alpha compositing with existing pixel self.pixels[x + y * self.width] = color; } } } } } Note that this code only works with opaque colors. If we added transparency (by reading the opacity property, or adding support for rgba() values in the CSS parser) then it would need to blend each new pixel with whatever it’s drawn on top of. Now we can put everything together in the paint function, which builds a display list and then rasterizes it to a canvas: /// Paint a tree of LayoutBoxes to an array of pixels. fn paint(layout_root: &LayoutBox, bounds: Rect) -> Canvas { let display_list = build_display_list(layout_root); let mut canvas = Canvas::new(bounds.width as uint, bounds.height as uint); for item in display_list.iter() { canvas.paint_item(item); } return canvas; } Lastly, we can write a few lines of code using the Rust Image library to save the array of pixels as a PNG file. Pretty Pictures At last, we’ve reached the end of our rendering pipeline. In under 1000 lines of code, robinson can now parse this HTML file: <div class="a"> <div class="b"> <div class="c"> <div class="d"> <div class="e"> <div class="f"> <div class="g"> </div> </div> </div> </div> </div> </div> </div> …and this CSS file: * { display: block; padding: 12px; } .a { background: #ff0000; } .b { background: #ffa500; } .c { background: #ffff00; } .d { background: #008000; } .e { background: #0000ff; } .f { background: #4b0082; } .g { background: #800080; } …to produce this: Yay! Exercises If you’re playing along at home, here are some things you might want to try: Write an alternate painting function that takes a display list and produces vector output (for example, an SVG file) instead of a raster image. Add support for opacity and alpha blending. Write a function to optimize the display list by culling items that are completely outside of the canvas bounds. If you’re familiar with OpenGL, write a hardware-accelerated painting function that uses GL shaders to draw the rectangles. To Be Continued… Now that we’ve got basic functionality for each stage in our rendering pipeline, it’s time to go back and fill in some of the missing features—in particular, inline layout and text rendering. Future articles may also add additional stages, like networking and scripting. I’m going to give a short “Let’s build a browser engine!” talk at this month’s Bay Area Rust Meetup. The meetup is at 7pm tomorrow (Thursday, November 6) at Mozilla’s San Francisco office, and it will also feature talks on Servo by my fellow Servo developers. Video of the talks will be streamed live on Air Mozilla, and recordings will be published there later. [Less]
Posted over 9 years ago by John
The same great people who brought RelEng Conf 2013 did it again earlier this year with the sold-out-wait-listed RelEng Conf 2014. Hosted at Google’s HQ campus, it was a great combination of academic and battle-hardened down-to-earth no-holds-barred ... [More] industry presentations and panel sessions. Unlike my keynote last year, this year I had no presentations, so I was able to relax and soak up the great keynote presentations by Chuck Rossi (RelEng at Facebook), and Dinah McNutt (RelEng at Google), as well as others. These are online, and well worth the watch: Chuck Rossi’s keynote is here: Dinah McNutt’s keynote is here: Closing panel discussion is here: Two years in a row of greatness from Bram, Christian, Foutse, Kim, Stephany, Akos and Boris means that I’m already looking forward to RelEng Conf 2015. Watch the official conference website, follow @relengcon and book your spot immediately to avoid that sad “oh, I’m still on the wait list” feeling. John. [Less]
Posted over 9 years ago by Chris Heilmann
Four years ago I announced that I will join Mozilla as principal evangelist and I was the happiest person alive. I exclaimed that I want Mozilla to be the “Switzerland of HTML5” and an independent player in the great browser wars around the early ... [More] days of this new technology revolution. I also announced that I am excited to use my flat more as I can work from home. Now I am here and I have hardly had the chance to do so as I was busy getting from event to event, training to training and meetup to meetup. And whilst this is exciting it is also superbly taxing. It is time to lean back a bit, relax and have some me time. I feel the first signs of burnout and I think it is very important to not let a fast and seemingly glamourous lifestyle on the road as an official spokesperson get in the way of finding peace and tranquility. I spoke in my last TEDx talk about getting too excited about one’s own online personality and living for that one and how dangerous that is. And here I am finding myself being excited about Chris on the road and forgot about Chris who just lets go and leaves things to sort themselves out. This is why I am taking a break from Mozilla. I am going on a sabbatical for a while and be a spectator watching the rewards of all the work we put in the last years. Firefox’s 10th anniversary is coming and great things are afoot. I think we’ve shown that we can be the “Switzerland of HTML5” and it is time for me to have some time for myself and see what my colleagues can do. That’s why I am stepping down as “the Mozilla guy” and be plain Chris for a while. I want to thank all my colleagues over the years for the great time I had. It is amazing to see how many dedicated and gifted people can work together and create something open and beautiful – even in traditionally very closed environments like the mobile space. I will of course be around and you will be able to meet me at selected events and online. People in London and Stockholm will also see more of me. I will only take it slower from now on until the new year and represent myself and not the large, amazing and wonderful world that is Mozilla. As it stated on one of our summits: it is one Mozilla and many voices. And I will lean back, listen, and enjoy. [Less]
Posted over 9 years ago
Just over a year ago I went to my first November Project San Francisco (NPSF) free workout. I'm not exactly sure why I chose that particular morning of 2013-10-30 to show up but a year later I'm very glad I did. It's the biggest physical ... [More] fitness change I've made since I first started running in January 2011. Newbie Seeing #NPSF chalkings in Golden Gate Park late summer of 2013 and especially meeting Sam Livermore and reading her enthusiastic posts had made me want to check it out. Maybe I decided on a whim the night before. Confession: I took a bus to my first November Project and it wasn't the only time. I woke up to a 6am alarm, made it to Haight & Masonic by 6:20, realized I wouldn't make it on time, and hopped on the 71 bus that was pulling up. Took it just a few blocks to Haight & Scott then jogged 2 blocks up to the park and ran out of breath on that slight incline. More on that later. I hiked up to the middle of Alamo Square, barely in time for introductions in the predawn darkness (just-before-PDT-to-PST-changeover). Standing on a rock on the edge of a circle of grass, dressed in a full-body penguin suit, NPSF founder and leader Laura McCloskey told us to hug someone we didn't know, and then introduce ourselves. Betny Townsend cheerily hugged me as a newbie, the first person I met at November Project. I saw Sam Livermore too. The open kindness of strangers and a familiar face was enough to make a strong positive impression. This was a workout group like no other. Laura explained the workout, which turned out to be a PR (personal record) Wednesday workout (as I've blogged previously, except thankfully in 2013 without the first lap around Alamo Square). It took me ~45-50 minutes by my watch and pretty much destroyed me. Exhausted and humbled I walked home. It was way out of my league. Yearbook Photos & The Huffman Two weeks later I noticed NPSF was taking yearbook photos so I decided to try it one more time. Same morning timing, took the bus again, ran out of breath again. That's me in the back near the left, with the white cap, red t-shirt, and white shorts, starting my second NPSF workout. This time we did what Laura called the "Huffman" partner workout, named after its inventor, Jessica Huffman. One person continuously does an exercise like pushups / sit-ups / lunges while the other runs a short downhill/uphill loop in the park as fast as they can, then they tag-off and swap places. We alternated for ~25 minutes working our way through two sets of four exercises if I remember correctly. Laura had us partner up with someone we didn't know, and that was how I met Erin Hallett, who also warmly welcomed me. I was starting to understand what NP was about. Partner workouts are very different, especially the Huffman. There's something about knowing that your partner is doing exercises non-stop while you're running that makes you push yourself paticularly hard, because you don't want to keep them waiting. And after we finished our sets, we did a final lap around Alamo Square lined up for yearbook photos. These photos turned out amazing. Rebecca Daniels photographed us in our fiercest post-workout faces, edited them and posted epic black and white headshots of everyone that showed up that day. I'm still using mine on my site and other sites too. (Reminder: NovemberProject 2014 Yearbook Photos Are Tomorrow!) Impressed and Scared By Hills One of the great things about NPSF is all the work the organizers put into not only the workouts themselves, but in documenting them, with group photos and blog posts. When the photos of the hills workouts started showing up, the incredible vistas, the small group of super athletes that participated, it was impressive and inspiring. I knew I could never do that. I can't run hills. When I started November Project, on all our runs around Alamo Square, downhill: no problem; uphill: I'd jog a few steps, and then have to walk the rest. Hills are scary because not being able to breathe is scary. Why I Ran Out Of Breath As embarrassed as I feel admitting to having taken the bus a few times to November Project, that's nothing compared to what I've told very few people about, which is that I grew up with asthma, and still wrestle with exertion induced asthma. In short that means if I start running from a cold start, after a dozen or so steps, my lungs feel anxious, my bronchial tubes start constricting, eventually each breath makes a louder audible wheezing sound, and I have to stop while I can still breathe standing up. That's why I ran out of breath after two blocks up a slight incline. I live on a reasonably steep street and could not run half a block up without having an attack. The way asthma attacks work for most people, either you have to get medication (i.e. use an inhaler), or you might also be able to rest, calm yourself down (if you've practiced various techniques beforehand), and recover in about 15-30 minutes. I tend to be fairly stubborn. I also hate admitting to weakness. There's an element of shame to it (even if there shouldn't be), and there's also an element of hey, everybody has issues they're dealing with, mine aren't special, don't look for any sympathy, just do your best. I also refused to run with my inhaler, because I'd rather learn my limits, and build self-confidence within those limits. I knew I could walk home if I had to. Secret Solo Hill Practice Going to November Project changed this for me. After participating a couple of times and being frustrated that I (was the only one who) couldn't run up the hills in Alamo Square, I decided to try practicing running uphill by myself even if it was only 25-50 feet at a time. When you've lived with asthma you learn to recognize what it feels like just before it happens. Hills workouts were out of the question, yet I knew if I very deliberately paced myself, breathed, and listened to that anxious feeling that builds in your lungs, I could push myself to that edge, and back down before an attack manifested. I wondered if repeatedly pushing to that edge might make a difference. From out my door I counted every house I could run up to before I had to stop and walk. One week I made it up a few houses to the green house. Next week I made it one more to the blue one. Another week the grey one. Then the tan one. Finally I was able to jog to the top of my block, just barely without losing my breath. I stopped and cried. I had run half a block uphill. I felt almost normal. Why Now It's something invisible that I live with. I'm not looking for sympathy or any special consideration; perhaps just understanding, and a broader understanding that you never know what anyone is going through, personally, privately, invisibly. We all have our struggles. I chose to write about this publicly for three reasons: Laura asked me what's my story. I couldn't tell it without this. It's part of who I am. Inspiration from Andrew and Shannon's posts of their personal stories & struggles. Most importantly, if I can help just one more person with asthma believe more in themselves then it's worth it. That they have more potential than they think they do, and to dare, to face the fear, to try, even in small steps, to find their limitations, persist, and maybe even grow beyond them. My First NPSF Hills Workout I kept practicing my own personal mini-hills workouts in secret. I kept running up my block, and beyond, up into Buena Vista Park, continuing my progress. Then NPSF announced a hills workout in Dolores Park on January 17th. Less than three months from my first time at NPSF, I decided to #justshowup to hills. Despite being familiar with Dolores Park, I was scared. I didn't care. I would run what I could, then walk if I had to. Judgment be damned. But of course there was none, no judgment. Everyone was nothing but encouraging. Yes I took the bus again that morning. It was a much smaller group than Wednesday. I met several NPSF regulars whose consistency had inspired me since I started: Josh Zipin (AKA "Zip"), Greg, Jorge , Pete Kruse, Adrienne, and more. I ran and made it most of the way up the Church street hill from 18th to 21st streets. I think I walked the last block. Then I ran down and up again. I finished four repeats before our 25 minutes were up. Apparently I could now do hills. Half Marathon, Running to Hills, and Track 16 days later, emboldened by the progress I'd made at NP, I ran my first half marathon (Kaiser) in 2:22. That particular cold, wet, solitary, painful experience is a story for another blog post. Suffice it to say it's still my PR, and I've been training hard to beat it, hopefully this Sunday at the Berkeley Half. I started going regularly to hills workouts, getting a ride, driving, carpooling, whatever it took. Finally a little over a month after that first time at hills, I ran with our "rungang" to the first NPSF Corona Heights hills workout. A week and a half after that I braved our informal trackattack workout and couldn't even keep up on the warmup laps. Didn't care. Just kept showing up and running nearly every week, twice a week at NP, and most Tuesdays at track. In just under 5 months I finally completed a trackattack workout. Positive Community — Just Show Up Despite all these personal triumphs, what November Project means to me is positive community: from smiles and eager hugs, to the coast-to-coast friendships, to last-minute Sunday long runs, to our informal #nopasoparungang which now consistently gets people to NPSF at least twice a week. My friend, one of the first people I met at NPSF, Natalie O'Connor asked me why I run. I told her, I run because I can. Everytime I walk outside in my running clothes, I know I've broken through limitations I thought I had, thanks to a supportive positive community like no other. [Less]
Posted over 9 years ago by Amy
Every app submitted to Firefox Marketplace and every add-on submitted to AMO is reviewed by a person; 60-80% of the time, that person is a volunteer. Each year, the AMMO team endeavors to meet a few of the top volunteer reviewers in person to talk ... [More] about the past year, get feedback, plan for the coming year, and have a pint or two. This year, we arranged a meetup at MozFest in London. We kicked things off with a welcome dinner and drinks, then spent the following day at the London MozSpace having more in-depth discussions. The group was extremely diverse—ten countries were represented among the 12 people who attended. Some reviewers joined in the past year, others have been reviewing for nearly a decade. One piece of feedback that really stuck with me was that many people think being an app reviewer is the only way to contribute to Marketplace. This means we need to do more to get the word out about the myriad ways one can get involved. But it also means the reviewer program is strong, and widely known, and these are reasons themselves for celebration. Notes from the meeting are available on this etherpad. We got some great feedback, and I am really looking forward to tackling some of the action items in the coming weeks. Afterwards, we attended the MozFest science fair kick-off together, then dispersed over the weekend to explore the event, letting serendipity and our own unique interests guide us. My interests and chance meetings guided me to make an LED robot, learn how to pick locks, and have fascinating discussions about communities and web literacy. Though I was weakened by flu at the conclusion of the weekend, I came away feeling invigorated by the spirit of Mozilla. [Less]
Posted over 9 years ago
Last week was the 2014 W3C TPAC. For those that don't know, TPAC is a conference where a number of W3C working groups get together in the same venue. This allows for a great amount of discussions between groups and also allows people to see what is ... [More] coming in the future of the web. The WebDriver Working Group was part of TPAC this year, like previous years, and there was some really great discussions. The main topics that were discussed were: We are going to be moving more discussions to the mailing list. This is to prevent people waiting for a Face to face to discuss things The Data model of how data is sent over the wire between the remote and local ends Attributes versus properties -This old chestnut An approach to moving some of the manual tests that are used for W3C specs to automated ones with WebDriver - This is exciting The meeting minutes for Thursday and Friday [Less]
Posted over 9 years ago
If you've come to any NovemberProject anywhere, make plans to be at the nearest one this Wednesday to get your yearbook photo. You've earned it. If you're a runner of any kind or have been curious about NovemberProject, check it out this ... [More] Wednesday and get your photo taken. Join us. If I've ever bugged you to come to NovemberProject, and you haven't yet, this is the day to do it. Trust me. I went to last year's Yearbook Photos day, had a great time (more on that in another post very soon!), and got a great photo that I'm still using for my site icon and profile photo. Facebook events - all Wednesday morning at ~6:15am: Los Angeles - Hollywood Bowl Minneapolis - Mill City Museum San Francisco - Alta Plaza Park Plus thirteen more cities (Check out November-Project.com for the full list). I'll add more direct city-event links as I find them. It looks like there's going to be a beautiful sunrise. [Less]
Posted over 9 years ago by Mike Kaply
If you haven't checked out the CCK2 lately, you should. One of the coolest features I've added recently is the ability to hide things on any arbitrary window that is opened by Firefox. For instance, if you want to hide the bottom box in the about ... [More] dialog, you can add "#aboutDialog #bottomBox" to the hidden UI section. You can also use it to hide arbitrary content in about:addons. I've also done major work on the clipboard capabilities API, so it should be more robust. There have also been quite a few bug fixes. You can keep up on all the latest changes here. Download the latest CCK2 by clicking here. If you want to request a feature, you can do so on the CCK2 support site. Priority for any requests is given to paying customers. And if the CCK2 saves you time and money, please consider getting a support contract. It ensures that I'll be able to keep working on the CCK2. [Less]
Posted over 9 years ago
42 changesets 98 files changed 2460 insertions 385 deletions ExtensionOccurrences js18 cpp16 h15 jsm7 java6 py3 ini3 txt2 in2 xml1 xhtml1 sjs1 mm1 json1 idl1 css1 cc1 c1 build1 ModuleOccurrences toolkit19 content11 mobile10 services9 ... [More] browser9 js5 layout4 dom4 ipc3 gfx3 widget1 testing1 modules1 media1 List of changesets: Richard NewmanBug 1090385 - More robust handling of external intents. r=snorp, a=sledru - 65515de095b8 Mark FinkleBug 895775 - Correctly handle lifecycle in GeckoNetworkManager. r=rnewman a=lmandel - ae19708887ef Richard NewmanBug 1090385 - Follow-up: fix GeckoAppShell. a=bustage - 0dd6a59ed6a5 Richard NewmanBug 1090385 - Follow-up: fix GeckoApp. a=bustage - 693b7d0c9b36 Richard NewmanBug 1090385 - Follow-up: fix yet more bustage in GeckoApp. a=bustage - 72bdce765298 Andrew McCreightBug 1089833 - Delete reply in MessageChannel::DispatchSyncMessage and DispatchInterruptMessage if channel isn't connected. r=billm, a=lsblakk - 926c3f3f1f3a Randell JesupBug 1087605 - Don't try to set the priority of the CCApp thread (which doesn't exist). r=bwc, a=lsblakk - e35984b580fb Boris ZbarskyBug 1087801 - Don't assume the global is a Window in the DOM CSS object. r=bholley, a=lsblakk - ac59c74b9386 Jonathan KewBug 1090869 - Don't collect output glyphs when checking for features involving . r=jdaggett, a=lsblakk - 17d3079dc41f Mike HommeyBug 1091118 - Also export RANLIB to unbust android builds on mac. r=gps, a=lmandel - 12a8a2d96453 Robert O'CallahanBug 1052900 - Restore -moz-win-exclude-glass handling to the way it worked before. r=tn, a=lsblakk - 73905ff57286 Drew WillcoxonBug 1083167 - Fix FormHistory error in ContentSearch by not passing an empty string to FormHistory.update. r=MattN, a=lmandel - cadb1112c8fb Doug TurnerBug 1073134 - Be more permissive on OSX 10.9.5 when parental control is on. r=jdm, a=lmandel - 340cfd2affa7 J. Ryan StinnettBug 1090450 - Properly check add-on update state during update interval. r=Mossop, a=lmandel - 06d2090db817 Michael WuBug 1081926 - Fallback on a simple image lookup when the normal lookup fails. r=mattwoodrow, a=lmandel - 546105a6d5c0 Jonathan WattBug 1076910 - Don't use gfxPlatform::GetPlatform() off the main thread. r=Bas, a=sledru - 8977f5061773 Jonathan WattBug 1076910 - Add some error checks to gfxUtils::EncodeSourceSurface. r=Bas, a=sledru - 3c329a6fd0cb Brian HackettBug 1084280 - Use a local RegExpStack when running the RegExp interpreter. r=jandem, a=dveditz - 631a73cdbc91 Brian HackettBug 1077514 - Execute regexps in the bytecode interpreter if the initial JIT execution was interrupted. r=jandem, a=lmandel - 5238acab8176 Mike de BoerBug 1089011: make sure to only import contacts that are part of the default contacts group. r=MattN a=lmandel - 8b1b897ca39c Bas SchoutenBug 1064864. Ensure the copying bounds are sane. r=jrmuizel a=sylvestre - d4ad7d727dd6 Georg FritzscheBug 1079341 - Missing yield on async makeDir in FHR state init. r=gps, a=lmandel - d9b49c7ee7fe Georg FritzscheBug 1064333 - Migrate the FHR client id to the datareporting service. r=gps, a=lmandel - 8fbc0d8bb83d Georg FritzscheBug 1064333 - Add the stable client id to the telemetry ping. r=froydnj, a=lmandel - ad6d502a38c9 Georg FritzscheBug 1064333 - Only add the stable user id to the ping when FHR upload is enabled. r=froydnj, a=lmandel - ec67776fc5e3 Georg FritzscheBug 1064333 - Init TelemetryPing in tests even if MOZILLA_OFFICIAL is not set. r=froydnj, a=lmandel - efb3c956dfef Georg FritzscheBug 1086252 - Show stable client id in about:telemetry. r=froydnj, a=lmandel - bda711062d08 Georg FritzscheBug 1069873 - Add counter histogram type. r=froydnj, ba=lmandel - a4db8f39f372 Georg FritzscheBug 1069953 - Part 1: Make min/max/bucket_count optional for nsITelemetry newHistogram(). r=froydnj, ba=lmandel - 56b3e37832b9 Georg FritzscheBug 1069874 - Add keyed histogram types. r=froydnj, ba=lmandel - 3fe1e43c97b8 Georg FritzscheBug 1092219 - Fix keyedHistogram.add() passing the wrong argument to Histogram::Add(). r=froydnj, a=lmandel - aa11e337b8e3 Georg FritzscheBug 1092176 - Add keyed histogram section in about:telemetry. r=froydnj, a=lmandel - e6db2f014e26 Georg FritzscheBug 1089670 - Record searches in Telemetry. r=bwinton, ba=lmandel - 1ca39da5df9d Paul AdenotBug 1085356 - Better handling of OSX audio output devices switching when SourceMediaStream are present in the MSG. r=jesup a=lmandel - 80b1fc2042df Randell JesupBug 1085356: Fix Mac audio output changes on older/different macs r=padenot a=lmandel - ddc951a77894 Randell JesupBug 1090415: Whitelist room.co for screensharing rs=mreavy a=lmandel - bf50cf09506c Randell JesupBug 1091031: Whitelist talky.io & beta.talky.io for screensharing rs=mreavy a=lmandel - 08876d848dcf Randell JesupBug 1085356: Bustage fix (missing include from merge) r=bustage a=bustage - f6a4136fe0af Nick AlexanderBug 1068051 - Add high-res device drawables. r=trivial, a=lmandel - 9f2160ac83d5 Richard NewmanBug 1084522 - Don't redefine layout attribute in IconTabWidget. r=lucasr, a=lmandel - 66297e95dc47 Richard NewmanBug 1084516 - Wrap Build.CPU_ABI access in deprecation annotation. r=snorp, a=lmandel - a02835abdd00 Olli PettayBug 1087633 - Filter out XPConnect wrapped input streams. r=bz, a=lmandel - 72938afdf993 [Less]
Posted over 9 years ago by Robert Nyman
Knowing your editor is important, and if it’s open source and you can add functionality, even better! Therefore, I dug into Atom from GitHub (which is open source!) to add something I like: a Hyperlink Helper. As mentioned in my recent posts on Vim ... [More] and favorite editors, I think it’s great for any developer to experiment and tweak their editor(s) of choice. Using Atom a bit on the side, I thought I’d look into how to create a package for it. It offers a lot of them already, browsable through the packages web site or through the within the app itself. Introducing the Hyperlink Helper Back in the day when I started using TextMate, one of my favorite functions was to have a keyboard shortcut to wrap the selected text with an <a> element and set its href attribute to what’s in the system clipboard. Then when I moved to Sublime Text, someone created the Hyperlink Helper package for Sublime Text. So, now with Atom, the next natural evolution would be for me to create one for it. How to install it Go to Settings in Atom > Packages: Search for Hyperlink Helper. Functionality Wraps selected text with an anchor element, e.g. Hello becomes <a href="http://robertnyman.com">Hello</a> Sets the href attribute of that anchor to what’s currently in the system clipboard How to trigger it Select some text in the current document Hit its keyboard shortcut:Ctrl + Cmd + L (Mac)Ctrl + Alt + L (Windows/Linux)or through Packages > hyperlink-helper > link in the Atom top menu Source code and improvements The source code is on GitHub – feel free to issue pull requests with improvements! Getting started building packages for Atom Does all this sound interesting and you want to build your own package? Then I recommend reading Creating Packages and Create Your First Package in the Atom docs. Atom also offers a way to generate a template package for you through the Package Generator: Generate Package in the Command Palette. This is triggered with: Cmd + Shift + p (Mac) Ctrl + Shift + p (Windows/Linux) Developer pro tip: in Atom, hit Cmd + . (Mac)/Ctrl + . (Windows/Linux) to show the Keybinding Resolver: great for seeing which command is connected with any keyboard shortcut combination you can come up with! (found via What are the keyboard shortcuts of the Atom editor? – keyboard shortcuts in Atom can also be found via Settings > Keybindings) Bonus: Hyperlink Helper for Vim Vim user and want a Hyperlink Helper? Just add this to your .vimrc file and call it via Space + l in Visual mode: vmap <Space>l c<a href="<C-r>+"><C-r>"</a> [Less]